提示: 核心需求就是Launcher3 去抽屉功能实现,要把所有抽屉应用放到桌面上。
文章目录
- 前言-需求
- 一、方案选型
-
- [1、更多应用-在原生Launcher3 基础上修改](#1、更多应用-在原生Launcher3 基础上修改)
- 2、更多应用自己写一个
- [3 、把原生Launch3 从系统源码分离出来-二次开发Launcher3源码-实现效果](#3 、把原生Launch3 从系统源码分离出来-二次开发Launcher3源码-实现效果)
- 二、方案实现
-
- [定制Launcher3 二次修改作为 更多应用App](#定制Launcher3 二次修改作为 更多应用App)
- 三、方案定制过程中遇到的坑点-困难点
-
- [1、直接更改Launcher3 实现更多应用效果](#1、直接更改Launcher3 实现更多应用效果)
- [2、默认自己Launcher-定制Launcher3 作为更多应用- 原生Launcher3 去除Home属性](#2、默认自己Launcher-定制Launcher3 作为更多应用- 原生Launcher3 去除Home属性)
- [3、默认自己Launcher-定制Launcher3 作为更多应用- 原生Launcher3 不去除Home属性](#3、默认自己Launcher-定制Launcher3 作为更多应用- 原生Launcher3 不去除Home属性)
-
- [开机后会让选择主程序界面-系统恢复出厂设置还是要选择Home 程序默认](#开机后会让选择主程序界面-系统恢复出厂设置还是要选择Home 程序默认)
- [多Launcher 实现默认主HOME 程序](#多Launcher 实现默认主HOME 程序)
- 四、个人经验建议-项目需求实现流程
-
- [经验-建议:如果是应用开发者-Launcher3经验一般-建议定制开发Launcher3 修改好的App源码修改](#经验-建议:如果是应用开发者-Launcher3经验一般-建议定制开发Launcher3 修改好的App源码修改)
- 解决虚拟按键点击无用问题
- [默认自己Launcher 作为默认默认Home程序](#默认自己Launcher 作为默认默认Home程序)
-
- [多Launcher 解决 多Home程序选择问题](#多Launcher 解决 多Home程序选择问题)
-
- [Android11 解决方案](#Android11 解决方案)
-
- [多个Launcher选择界面直接跳转到指定Home 程序](#多个Launcher选择界面直接跳转到指定Home 程序)
- [Android15 解决方案](#Android15 解决方案)
-
- [点击Home 按键 回到 首页-定制首页](#点击Home 按键 回到 首页-定制首页)
- 开机默认跳转到指定HOME程序
- 解决方案-小结
- 总结
前言-需求
直接看目前需求吧:要实现如下公版软件需求,细节需求:
更多应用完全用原生Launcher3 的效果。

需求思路
所以针对如上需求,最直接的就是修改原生Launcher,原生Launcher3 直接去抽屉,然后点击更多应用跳转到原生Launcher3 即可。
一、方案选型
1、更多应用-在原生Launcher3 基础上修改
这种方案其实最直接的,最优效果,完全直接使用Launcher3 的效果。 直接跳转到原生Launcher3 的更多应用界面(抽屉模块);或者跳转到Launcher3 默认的主界面,但是主界面需要把所有应用显示出来同时去掉抽屉。
参考资料
Android11-Launcher3 定制-去除副屏幕-可以滑动效果
Android11-Launcher3 定制-去除副屏幕-可以滑动效果 - 篇二
或者其他网上很多参考资料,可以参考。
难点-困难点-说明
这种直接在原生Launcher3 上面修改方案,肯定最直接最优解。 但是难度系数很大,如果你不是很熟悉Launcher3 源码,或者 还没有研究过、做过Launcher3 相关开发 或者没有研究过。那么就需要花点时间 熟悉架构、熟悉不同Android版本流程,进行Launcher3 定制。
- 不同Android版本,Launcher3 对应的源码有稍微区别,遇到问题现象也不一样的,对于快捷方式的代码需要稍微修改,所以需要你熟悉Launcher3 源码 这个是必须条件。
- 遇到普遍最大问题是: 桌面为空,无法显示出来应用,主界面第一次无法创建盒子布局,重启后才会出现;桌面无法显示已经安装的快捷应用。
只有实际开发中才会遇到各种问题,不同Android 会遇到不一样的问题,需要针对性修改实现。
2、更多应用自己写一个
第二种方案是自己写一个更多应用,加载出所有App 不就行了嘛。 这种方案是最简单的,但是体验最差,达不到Launcher3 的各种功能和UI效果。
3 、把原生Launch3 从系统源码分离出来-二次开发Launcher3源码-实现效果
网上有相关已经去掉抽屉的原生Launcher,直接在这些Launcher上面开发实现更多应用效果,更改包名不要和原生Launcher3 重名。 那么 需要做的就是:
- 原生Launcher3 作为普通应用(去掉Home属性)、或者 原生Launcher3 不默认为主界面Home程序。
- 定制二次开发的Launcher3 更改为普通的更多应用App 。
- 主Home程序写一个简单的调用
二、方案实现
定制Launcher3 二次修改作为 更多应用App
源码路径: Launcher3 去抽屉功能
实现效果如下:
更多应用-主界面效果

更多应用-可拖拽效果

更多应用-文件夹效果

更多应用-长按-应用信息显示

更多应用本质
更多应用实际上就是一个定制版的Launcher3 程序,然后去掉Home 属性,其它应用直接打开显示就是更多应用效果。 如果把Home 程序加上,它实际上就是一个定制版本的Launcher3 程序。
三、方案定制过程中遇到的坑点-困难点
1、直接更改Launcher3 实现更多应用效果
第一次开机无法显示快捷到主界面
Android11 网上是有资料的可以实现,但是 Android15 目前网上资料比较少 可以修改成功。但是第一次 无法显示更多应用快捷到主界面。
2、默认自己Launcher-定制Launcher3 作为更多应用- 原生Launcher3 去除Home属性
底部虚拟按键-最近历史任务快捷键失效
因为自己开发了Launcher,那么开机启动就需要启动自己的Launcher,所以直接把Launcher3 的Home 属性去掉即可。 实际发现去掉之后 虚拟按键-最近历史任务 按键失效。 在MTK平台上面是没有问题的,但是在Rk Android11 和 Android15 上面都有问题的。
3、默认自己Launcher-定制Launcher3 作为更多应用- 原生Launcher3 不去除Home属性
开机后会让选择主程序界面-系统恢复出厂设置还是要选择Home 程序默认
多Launcher 界面,会让选择Launcher 程序,让选择默认Home 程序。
多Launcher 实现默认主HOME 程序
这里面有两个知识点:
- 开机默认打开主程序
- 点击HOME 程序,一定要返回到自己开发的Launcher 程序,不可回到系统原生Launcher3程序
四、个人经验建议-项目需求实现流程
经验-建议:如果是应用开发者-Launcher3经验一般-建议定制开发Launcher3 修改好的App源码修改
如果你是应用开发者,定制Launcher3 是有难度的,直接拿提供的资料和网上资料参考,对应用进行定制实现更多应用功能。 Launcher3 去抽屉功能。 不建议 直接修改系统源码Launcher3,定制有一定难度的。
解决虚拟按键点击无用问题
Rk平台中,无论Android11 还是 Android15 都要求有原生Launcher3 存在的,虚拟按键才能正常工作。所以集成自己定制Launcher 程序,系统原生自带Launcher3 必须要有Home 属性。
默认自己Launcher 作为默认默认Home程序
强烈参考之前源码解读和思路解读:Android 动态设置默认Launcher(默认应用 电话-短信-浏览器-主屏幕应用))
说白了如何去设置指定的Launcher作为默认Home 程序。 自己就放在自己应用里面吧,在App 里面Application 实现,设置自己作为默认HOME 程序。
java
private fun setDefaultHome() {
val ISFirstLaunch= MmkvHelper.getInstance().mmkv.getInt(IS_FISRT_LAUNCHER_APP,0)
Log.d(TAG,"=========ISFirstLaunch:$ISFirstLaunch======")
if(ISFirstLaunch==0){
Log.d(TAG,"========= 第一次启动,重新设置 HOME 程序======")
val roleManager: RoleManager =
ContextProvider.get().context.getSystemService<RoleManager>(RoleManager::class.java)
val executor: Executor = ContextProvider.get().context.getMainExecutor()
val callback =
Consumer<Boolean> { successful: Boolean ->
if (successful) {
Log.i(TAG, " 成功了==> Package " + "added" + " as role holder, role: " + "测试Home 桌面" + ", package: " )
} else {
Log.i(TAG, " 失败了==> Package " + "added" + " as role holder, role: " + "测试Home 桌面" + ", package: " )
}
}
val addRoleHolderAsUser = roleManager.javaClass.getMethod(
"addRoleHolderAsUser",
String::class.java, String::class.java, Int::class.java,
UserHandle::class.java, Executor::class.java, Consumer::class.java
)
addRoleHolderAsUser.isAccessible = true
val userHandle = NavigationHelper.newInstance(
UserHandle::class.java, arrayOf<Class<*>?>(
Int::class.javaPrimitiveType
), 0
) as UserHandle
addRoleHolderAsUser.invoke(roleManager, "android.app.role.HOME", "com.fise.dmseries",
1,userHandle,executor,callback)
MmkvHelper.getInstance().mmkv.putInt(IS_FISRT_LAUNCHER_APP,1);
}else{
Log.d(TAG,"=========非 第一次启动 不处理======")
}
}
多Launcher 解决 多Home程序选择问题
直接在对应界面 结束当前界面并跳转到自己定制的Launcher.
Android11 解决方案
多个Launcher选择界面直接跳转到指定Home 程序
直接在Home 选择界面跳转到自己的Home程序不就行了嘛
路径:base/core/java/com/android/internal/app/ResolverActivity.java
java
diff --git a/frameworks/base/core/java/com/android/internal/app/ResolverActivity.java b/frameworks/base/core/java/com/android/internal/app/ResolverActivity.java
index fadc15912d..01fb5bf497 100644
--- a/frameworks/base/core/java/com/android/internal/app/ResolverActivity.java
+++ b/frameworks/base/core/java/com/android/internal/app/ResolverActivity.java
@@ -102,6 +102,13 @@ import java.util.Objects;
import java.util.Set;
+// modify by fangchen start
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+// modify by fangchen end
+
+
/**
* This activity is displayed when the system attempts to start an Intent for
* which there is more than one matching activity, allowing the user to decide
@@ -343,7 +350,51 @@ public class ResolverActivity extends Activity implements
List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
setTheme(appliedThemeResId());
super.onCreate(savedInstanceState);
-
+
+
+ // modify by fangchen start
+
+
+ try {
+ // Intent intent = getIntent();
+ if (intent != null && Intent.ACTION_MAIN.equals(intent.getAction())
+ && intent.hasCategory(Intent.CATEGORY_HOME)) {
+
+
+ ComponentName myHomeComponent = new ComponentName(
+ "com.fise.dmseries",
+ "com.fise.dmseries.ui.main.MainActivity"
+ );
+
+
+ /* PackageManager pm = getPackageManager();
+ pm.setPreferredActivity(
+ intent,
+ IntentFilter.MATCH_CATEGORY_TYPE,
+ null,
+ myHomeComponent,
+ UserHandle.USER_CURRENT
+ );
+ */
+
+ intent.setComponent(myHomeComponent);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+
+
+ finish();
+ return;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+
+ // modify by fangchen end
+
+
+
+
Android15 解决方案
其实在Android15 上面 沿用Android11 的方案也是可以的,这里给出另外一种方案
java
modified: base/services/core/java/com/android/server/policy/PhoneWindowManager.java 【点击HOME 按键跳转到指定Home 程序】
modified: base/services/core/java/com/android/server/wm/RootWindowContainer.java 【开机直接跳转到 指定HOME程序】
点击Home 按键 回到 首页-定制首页
这里其实是多余操作,因为开机后跳转到指定 HOME 程序,指定HOME程序第一次打开会去指定默认HOME程序的,所有点击HOME程序一定回到指定HOME程序的。 但是这里映射按键点击触发知识点蛮多的,都是在这个类里面定制修改 业务逻辑的。
java
--- a/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3518,7 +3518,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
switch (keyCode) {
case KeyEvent.KEYCODE_HOME:
- return handleHomeShortcuts(focusedToken, event);
+ // modify by fangchen start
+ //return handleHomeShortcuts(focusedToken, event);
+
+ Intent intentHome = new Intent();
+ intentHome.setComponent(new ComponentName(
+ "com.fise.dmseries",
+ "com.fise.dmseries.ui.main.MainActivity"
+ ));
+ intentHome.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intentHome);
+ Log.d(TAG, "====interceptSystemKeysAndShortcuts==== KeyEvent.KEYCODE_HOME==== = ");
+
+ return true;
+ // modify by fangchen end
+
case KeyEvent.KEYCODE_RECENT_APPS:
if (firstDown) {
showRecentApps(false /* triggeredFromAltTab */);
开机默认跳转到指定HOME程序
保证每次开机跳转到指定HOME程序
java
+// modify by fangchen start
+import android.util.Log;
+// modify by fangchen end
+
+
/** Root {@link WindowContainer} for the device. */
class RootWindowContainer extends WindowContainer<DisplayContent>
implements DisplayManager.DisplayListener {
@@ -1484,7 +1489,68 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
*/
@VisibleForTesting
ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
- final int flags = ActivityManagerService.STOCK_PM_FLAGS;
+
+
+
+
+ // modify by fangchen start
+ ComponentName myHome = new ComponentName(
+ "com.fise.dmseries",
+ "com.fise.dmseries.ui.main.MainActivity");
+ ActivityInfo aInfo = null;
+ try {
+ aInfo = mService.getPackageManagerInternalLocked()
+ .getActivityInfo(myHome,
+ android.content.pm.PackageManager.GET_ACTIVITIES
+ | android.content.pm.PackageManager.MATCH_SYSTEM_ONLY,
+ userId, 0);
+
+ } catch (Exception e) {
+ }
+
+
+ if (aInfo != null) {
+ aInfo = new ActivityInfo(aInfo);
+ aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
+ return aInfo;
+ }
+
+ final int flags = ActivityManagerService.STOCK_PM_FLAGS;
+ final ComponentName comp = homeIntent.getComponent();
+ aInfo = null;
+ try {
+ if (comp != null) {
+ // Factory test.
+ aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
+ } else {
+ final String resolvedType =
+ homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
+ final ResolveInfo info = mTaskSupervisor.resolveIntent(homeIntent, resolvedType,
+ userId, flags, Binder.getCallingUid(), Binder.getCallingPid());
+ if (info != null) {
+ aInfo = info.activityInfo;
+ }
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+
+ if (aInfo == null) {
+ Slogf.wtf(TAG, new Exception(), "No home screen found for %s and user %d", homeIntent,
+ userId);
+ return null;
+ }
+
+ aInfo = new ActivityInfo(aInfo);
+ aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
+ return aInfo;
+
+
+
+ // modify by fangchen end
+
+
+ /*final int flags = ActivityManagerService.STOCK_PM_FLAGS;
final ComponentName comp = homeIntent.getComponent();
ActivityInfo aInfo = null;
try {
@@ -1512,7 +1578,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
- return aInfo;
+ return aInfo;*/
}
@VisibleForTesting
解决方案-小结
- 如上,其实Android11 解决方案也有弊端的,也需要跟Android15 一样,设置系统开机一定是去启动默认地址的Launcher HOME程序。不然 在系统设置里面点击了 原生Launcher3 作为HOME程序,那么就没法实现开机默认打开定制HOEM程序了。
- 不同的Android 版本,系统 Framework层API稍有改动不一致,遇到实际问题自己思考,实现需求,定制源码。
总结
- 这个需求里面涉及到的Launcher3 知识点其实是海量的,蛮多的,如果有兴趣可以自行研究。
- Launcher3 定制开发一个更多应用功能。对于初学者或者Framework初学者 更能轻松入局,解决实际项目需求。 Launcher3 去抽屉功能
- 如果有时间,可以研究Launcher3 源码,这里面有大量的Launcher3 架构、绑定数据、数据加载、UI效果知识点,不同版本 还有区别,需要深入研究。
- 上面提供的定制Launcher3 开发 更多应用最大的益处 不用进行系统开发多版本适配,直接用。