- 不保留系统launcher
在mk文件中添加这个属性LOCAL_OVERRIDES_PACKAGES := Launcher3 对应的mk中删除,不让其编译即可。
- 保留系统默认的Launcher
当系统存在多个launcher时,若没有设置默认launcher,开机启动后会弹出提示框,罗列所有launcher,用户选择并设置了默认launcher后,按home键以及以后重启都会进入默认的launcher。亦或者在设置--》应用和通知--》默认应用--》主屏幕应用 中也可设置默认launcher。
客户希望系统能直接就进入我设定的launcher而不是弹出框后选择然后设置
前提:客户的app需要有home属性
修改方法:
首先我们需要增加全局属性Settings.Global.DEFAULT_LAUNCHER,,客户可通过修改该属性设置自定义桌面
1:增加自定义属性://frameworks\base\core\java\android\provider\Settings.java public static final class Global extends NameValueTable { public static final String DEFAULT_LAUNCHER = "my_default_launcher"; }public static final class System extends NameValueTable { public static final String DEFAULT_LAUNCHER = Global.DEFAULT_LAUNCHER; PUBLIC_SETTINGS.add(DEFAULT_LAUNCHER); MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_LAUNCHER); }frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java private void loadGlobalSettings(SQLiteDatabase db) { loadStringSetting(stmt, Settings.Global.DEFAULT_LAUNCHER, R.string.default_launcher); } //frameworks\base\packages\SettingsProvider\res\values\defaults.xmlcom.android.launcher3/com.android.launcher3.Launcher
两种方法可选:
- 修改弹出框界面直接设置launcher,弹出提示框界面是:frameworks/base/core/java/com/android/internal/app/ResolverActivity.java:修改方法:在configureContentView内直接读取自定义的桌面,然后替代launcher3
1:frameworks/base/core/java/com/android/internal/app/ResolverActivity.java 的configureContentView 读取设置的默认桌面,进行设置,mResolvingHome就是表示需要选择的是不是home在这里只针对home作处理。public boolean configureContentView(List payloadIntents, Intent[] initialIntents, List rList) { //.... if (rebuildCompleted) { //.... //phoebe add for default launcher for prop Settings.Global.DEFAULT_LAUNCHER if(mResolvingHome){ String defaultlauncher = Settings.Global.getString(getContentResolver(), Settings.Global.DEFAULT_LAUNCHER); final TargetInfo defaultTarget = mAdapter.targetInfoForDefault(defaultlauncher); Log.d(TAG, "zmm add for configureContentView:defaultlauncher:" + defaultlauncher + ":" + defaultTarget); if (defaultTarget != null) { safelyStartActivity(defaultTarget); mPackageMonitor.unregister(); mRegistered = false; finish(); return true; } } }}2:在ResolveListAdapter 增加targetInfoForDefault方法,并且在rebuildList成功以后,再次设置默认laucnher public class ResolveListAdapter extends BaseAdapter { @Nullablepublic TargetInfo targetInfoForDefault(String info) { if (TextUtils.isEmpty(info)) { return null; } //com.yjx.inoexdash/com.yjx.inoexdash.ui.main.MainActivity String[] namesArray = info.trim().split("/"); if (namesArray == null || namesArray.length < 2) { return null; } String packageName = namesArray[0]; String activityInfo = namesArray[1]; if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(activityInfo)) { return null; } ComponentName componentName = new ComponentName(packageName.trim(), activityInfo.trim()); Log.d(TAG, "zmm add for targetInfoForDefault:" + componentName + ":" + mDisplayList.size()); for (TargetInfo targetInfo : mDisplayList) { ComponentName targetComponentName = targetInfo.getResolvedComponentName(); if (componentName.equals(targetComponentName)) { return targetInfo; } } return null;} private void postListReadyRunnable() { if (mPostListReadyRunnable == null) { mPostListReadyRunnable = new Runnable() { @Override public void run() { //phoebe add for default launcher for prop Settings.Global.DEFAULT_LAUNCHER String defaultlauncher = mResolvingHome ? Settings.Global.getString(context.getContentResolver(), Settings.Global.DEFAULT_LAUNCHER) : null; final TargetInfo defaultTarget = TextUtils.isEmpty(defaultlauncher) ? null : mAdapter.targetInfoForDefault(defaultlauncher); Log.d(TAG, "zmm add for postListReadyRunnable defaultlauncher:" + defaultlauncher + ":" + defaultTarget); if (defaultTarget != null) { safelyStartActivity(defaultTarget); finish(); return; } setHeader(); resetButtonBar(); onListRebuilt(); mPostListReadyRunnable = null; } }; getMainThreadHandler().post(mPostListReadyRunnable); }}}
修改ActivityManagerService 跳过ResolverActivity
1:ActivityStartController 的startHomeActivity方法内读取用户设置的桌面,并且跳过Settings,和Provision因为第一次开机,会先Settings的CryptKeeper(加密),FallbackHome(设备正在启动中)接着是provision 的默认桌面,再是launcher3的Launcher页面zmm add for startHomeActivity...com.android.settings.CryptKeeper:ComponentInfo{com.android.settings/com.android.settings.CryptKeeper} zmm add for startHomeActivity...com.android.settings.FallbackHome:ComponentInfo{com.android.settings/com.android.settings.FallbackHome} zmm add for startHomeActivity...com.android.provision.DefaultActivity:ComponentInfo{com.android.provision/com.android.provision.DefaultActivity} zmm add for startHomeActivity...com.android.launcher3.Launcher:ComponentInfo{com.android.launcher3/com.android.launcher3.Launcher}//frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.javavoid startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) { final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); if (!ActivityRecord.isResolverActivity(aInfo.name)) { // The resolver activity shouldn't be put in home stack because when the foreground is // standard type activity, the resolver activity should be put on the top of current // foreground instead of bring home stack to front. options.setLaunchActivityType(ACTIVITY_TYPE_HOME); } //phoebe add for default launcher for prop Settings.Global.DEFAULT_LAUNCHER skip settings,Provision String shortName = (intent == null || intent.getComponent() == null) ? null : intent.getComponent().getPackageName(); if (!isSettingsApp(shortName) && !isProvisionApp(shortName) && setTargetActivityAsPreferredActivity()) { //Slog.d(TAG, " zmm add for startHomeActivity as user seetings.."); return; } //phoebe add for default launcher for prop Settings.Global.DEFAULT_LAUNCHER skip settings,Provision end ... }//判断是不是Settings app private boolean isSettingsApp(String shortName) { return shortName != null && shortName.equals("com.android.settings"); }//判断是不是Provision app private boolean isProvisionApp(String shortName) { return shortName != null && shortName.equals("com.android.provision"); }//设置用户设置的桌面 private boolean setTargetActivityAsPreferredActivity() { boolean result = false; Context context = mService.mContext; if (context == null) return result; String info = Settings.Global.getString(context.getContentResolver(), Settings.Global.DEFAULT_LAUNCHER); Slog.d(TAG, " zmm add for setTargetActivityAsPreferredActivity info=" + info); if (TextUtils.isEmpty(info)) { return result; } String[] namesArray = info.split("/"); if (namesArray == null || namesArray.length < 2) { return result; } String packageName = namesArray[0]; String activityInfo = namesArray[1]; if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(activityInfo)) { return result; } IntentFilter filter = new IntentFilter(); filter.addAction("android.intent.action.MAIN"); filter.addCategory("android.intent.category.HOME"); filter.addCategory("android.intent.category.DEFAULT"); Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); packageName = packageName.trim(); activityInfo = activityInfo.trim(); PackageManager pm = context.getPackageManager(); List list = pm.queryIntentActivities(intent, 0); final int N = list == null ? 0 : list.size(); ComponentName[] set = new ComponentName[N]; ComponentName componentName = null; int bestMatch = 0; for (int i = 0; i < N; i++) { ResolveInfo r = list.get(i); set[i] = new ComponentName(r.activityInfo.packageName, r.activityInfo.name); if (r.match > bestMatch) bestMatch = r.match; if (packageName.equals(r.activityInfo.packageName) && activityInfo.equals(r.activityInfo.name)) { componentName = set[i]; } }// Slog.e(TAG, "zmm add for setTargetActivityAsPreferredActivity newcomponentName=" + componentName); if (null != componentName) { pm.replacePreferredActivity(filter, IntentFilter.MATCH_CATEGORY_EMPTY, set, componentName); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); result = true; } return result; }2:接着修改frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,需要把用户在设置--》默认应用中选择的桌面应用保存到自定义的属性中。ComponentName getHomeActivitiesAsUser(List allHomeCandidates, int userId) { ... for (int i = 0; i < resolveInfosSize; i++) { ResolveInfo resolveInfo = resolveInfos.get(i); if (resolveInfo.activityInfo != null && TextUtils.equals( resolveInfo.activityInfo.packageName, packageName)) { //phoebe add start ComponentName componentName = new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); Slog.d(TAG, "zmm add for getHomeActivitiesAsUser:com:"+componentName); String value = resolveInfo.activityInfo.packageName + "/" + resolveInfo.activityInfo.name; android.provider.Settings.Global.putString(mContext.getContentResolver(), android.provider.Settings.Global.DEFAULT_LAUNCHER, value); //phoebe add end return componentName; } } return null; }
以上两种都可实现根据用户配置切换默认launcher
1:adb 切换adb shell settings put global my_default_launcher com.android.launcher3/com.android.launcher3.Launcher2:app可如此调用:Settings.Global.putString(getContentResolver(), "my_default_launcher", "com.yjx.inoexdash/com.yjx.inoexdash.ui.main.MainActivity");
客户的app如果是普通的三方app,设置Global属性可能是报错没有权限:
Settings.Global.putString(getContentResolver(), "my_default_launcher", "com.yjx.inoexdash/com.yjx.inoexdash.ui.main.MainActivity");报错:缺少权限:Manifest.permission.WRITE_SECURE_SETTINGS该权限是系统app才能申请的权限,普通app申请不到的话,我们可以去掉该限制。diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -1249,18 +1250,23 @@ public class SettingsProvider extends ContentProvider { private boolean mutateGlobalSetting(String name, String value, String tag, boolean makeDefault, int requestingUserId, int operation, boolean forceNotify, int mode) {- // Make sure the caller can change the settings - treated as secure. - enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS); String pkg = "com.android.settings"; //数据写入时使用系统settings应用的包名,系统会进行调用进程的包名判断 if(!"my_default_launcher".equals(name)){ //phoebe add 自定义数据不进行权限验证 pkg = ""; // Make sure the caller can change the settings - treated as secure. enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS); }//下面修改在插入操作时使用上面预设的包名,绕过包名验证@@ -1268,7 +1274,7 @@ public class SettingsProvider extends ContentProvider { case MUTATION_OPERATION_INSERT: { return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM, name, value, tag, makeDefault,-getCallingPackage(), forceNotify, CRITICAL_GLOBAL_SETTINGS);+"".equals(pkg)?getCallingPackage():pkg, forceNotify, CRITICAL_GLOBAL_SETTINGS); }
每日语录:滴水穿石!!!加油!!!
单曲循环《如愿》
来源地址:https://blog.csdn.net/androidzmm/article/details/128285753