设置默认launcher

平台:android O

需求

手机中有多个launcher,需要给每个用户设置一个默认的Launcher(每类用户是同一个),考虑到android的多用户问题,不单是第一次开机要设置,每一次创建新的用户(user,guest,owner) 都要去设置一个默认的,并且要保证每个用户修改为自己喜欢的Launcher后,重启机器不能去覆盖用户的设置.

思路

1.在手机的’/data/system/users/‘目录下.有用户的列表,以及用户的文件夹,比如owner用户是0文件夹,在文件夹里有一个偏好设置保存的文件:package-restrictions.xml.
2.作为owner用户,可以在第一次开机的时候对其进行设置,作为其他用户可以在创建的时候去设置;

先把方案给出: 需要修改三个文件: frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java frameworks/base/packages/SystemUI/AndroidManifest.xml UserManagerService.java—>createUserInternalUnchecked

  1. } finally {
  2. Binder.restoreCallingIdentity(ident);
  3. }
  4. mPm.setDefaultLauncherAsUser(userId);//add
  5. return userInfo;
  6. }

PackageManagerService.java—>systemReady最后添加:
setDefaultLauncher();

在PackageManagerService.java添加两个方法:

  1. public void setDefaultLauncher(){
  2. if(isFirstBoot()) {
  3. setDefaultLauncherAsUser(0);//owner用户第一次开机进行设置
  4. }
  5. }
  6. public void setDefaultLauncherAsUser(int userId){//给普通user用户和guest用户使用,
  7. final PackageManager mPm = mContext.getPackageManager();
  8. Intent homeIntent=new Intent();
  9. homeIntent.addCategory(Intent.CATEGORY_HOME);
  10. homeIntent.setAction(Intent.ACTION_MAIN);
  11. homeIntent.addCategory(Intent.CATEGORY_DEFAULT);
  12. String defaultLauncherPkg = "com.test.launcher";
  13. String defaultLauncherClass = "com.test.launcher.Launcher");
  14. ResolveInfo info = mPm.resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY);
  15. ComponentName DefaultLauncher=new ComponentName(defaultLauncherPkg,defaultLauncherClass);
  16. ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
  17. ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
  18. ComponentName[]mHomeComponentSet = new ComponentName[homeActivities.size()];
  19. for (int i = 0; i < homeActivities.size(); i++) {
  20. final ResolveInfo candidate = homeActivities.get(i);
  21. final ActivityInfo activityInfo= candidate.activityInfo;
  22. ComponentName activityName = new ComponentName(activityInfo.packageName, activityInfo.name);
  23. mHomeComponentSet[i] = activityName;
  24. }
  25. IntentFilter mHomeFilter = new IntentFilter(Intent.ACTION_MAIN);
  26. mHomeFilter.addCategory(Intent.CATEGORY_HOME);
  27. mHomeFilter.addCategory(Intent.CATEGORY_DEFAULT);
  28. mPm.addPreferredActivityAsUser(mHomeFilter, IntentFilter.MATCH_CATEGORY_EMPTY,mHomeComponentSet, DefaultLauncher, userId);
  29. }

PackageManagerService.java—>findPreferredActivity

  1. // Okay we found a previously set preferred or last chosen app.
  2. // If the result set is different from when this
  3. // was created, we need to clear it and re-ask the
  4. // user their preference, if we're looking for an "always" type entry.
  5. if (always && !pa.mPref.sameSet(query)) {
  6. if (!(intent.getAction() != null
  7. && intent.getAction().equals(intent.ACTION_MAIN)
  8. && intent.getCategories() != null
  9. && intent.getCategories().contains(intent.CATEGORY_HOME))) {//add 添加过滤条件
  10. Slog.i(TAG, "Result set changed, dropping preferred activity for "
  11. + intent + " type " + resolvedType);
  12. if (DEBUG_PREFERRED) {
  13. Slog.v(TAG, "Removing preferred activity since set changed "
  14. + pa.mPref.mComponent);
  15. }
  16. pir.removeFilter(pa);
  17. // Re-add the filter as a "last chosen" entry (!always)
  18. PreferredActivity lastChosen = new PreferredActivity(
  19. pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false);
  20. pir.addFilter(lastChosen);
  21. changed = true;
  22. return null;
  23. }
  24. }

frameworks/base/packages/SystemUI/AndroidManifest.xml添加设置偏好的权限.
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />

解决该问题遇到的坑以及参考的有价值的文章:

1号坑

网上有不少方案修改packages/apps/Provision,该方案是可行的,但是会带来问题
1.会设置两次默认值,导致第一次开机解锁后会出现闪屏;
2.开机时间加长.

2号坑

直接配置一个默认的xml,让其加载到默认设置package-restrictions.xml中. 很可惜,该方案对其他默认APP有效,对Launcher无效.具体分析参考:
[1] http://www.dxjia.cn/2016/03/08/aosp-default-application-setting/ “Android源码设置default application” [2] https://stackoverflow.com/questions/34073290/set-default-application-on-aosp “为什么不能设置Launcher?”

3号坑

如果不添加SET_PREFERRED_APPLICATIONS权限,在Launcher界面下拉菜单添加user或者guest导致system UI crash.

思考: 1.owner也是用户,可以将设置默认launcher的代码写在一个共同的节点代码.目前没有找到. 2.最好使用PackageManager.addPreferredActivityAsUser方法,PackageManager.replacePreferredActivityAsUser