zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

Android如何设置默认的Launcher

Android 如何 设置 默认 Launcher
2023-09-14 09:04:19 时间

问题
机器装有多个launcher,第一次开机,系统会弹出让用户选择哪个作为默认launcher的对话框,但是客户不希望看到这个框,默认使用其中的一个launcher

涉及代码
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

修改方法
在ActivityManagerService中的startHomeActivityLocked之前,将客户希望的launcher设置到系统的addPreferredActivity(mPreferredActivities)当中,对应的xml配置文件在/data/system/users/0/package-restrictions.xml 当中,例如

<preferred-activities>
    <item name="com.test.touch.homescreen/.MainActivity" match="100000" always="true" set="2">
        <set name="com.test.touch.homescreen/.MainActivity" />
        <set name="com.android.launcher3/.Launcher" />
        <filter>
            <action name="android.intent.action.MAIN" />
            <cat name="android.intent.category.HOME" />
            <cat name="android.intent.category.DEFAULT" />
        </filter>
    </item>
</preferred-activities>

修改方法
svn diff

  • //if no preferered launcher activity exist, set the default one
  • private void setDefaultLauncher(int userId) {
  •    // get default component
    
  •    String packageName = "com.test.touch.homescreen";
    
  •    String className = "com.test.touch.homescreen.MainActivity";
    
  •    IPackageManager pm = ActivityThread.getPackageManager();
    
  •    //判断指定的launcher是否存在
    
  •           Slog.i(TAG, "setDefaultLauncher packageName " + packageName + " className " + className);
    
  •    if (hasApkInstalled(packageName)) {
    
  •        Slog.i(TAG, "default packageName = " + packageName + ", default className = " + className);
    
  •        ArrayList<IntentFilter> intentList = new ArrayList<IntentFilter>();
    
  •        ArrayList<ComponentName> cnList = new ArrayList<ComponentName>();
    
  •        mContext.getPackageManager().getPreferredActivities(intentList, cnList, null);
    
  •        IntentFilter dhIF = null;
    
  •        for (int i = 0; i < cnList.size(); i++) {
    
  •            dhIF = intentList.get(i);
    
  •            if (dhIF.hasAction(Intent.ACTION_MAIN) && dhIF.hasCategory(Intent.CATEGORY_HOME)) {
    
  •                Slog.i(TAG, "default launcher exist = " + cnList.get(i).getPackageName());
    
  •                return;
    
  •            }
    
  •        }
    
  •        //获取所有launcher activity
    
  •        Intent intent = new Intent(Intent.ACTION_MAIN);
    
  •        intent.addCategory(Intent.CATEGORY_HOME);
    
  •        intent.addCategory(Intent.CATEGORY_DEFAULT);            
    
  •                   List<ResolveInfo> list = new ArrayList<ResolveInfo>();
    
  •        try {
    
  •            list = pm.queryIntentActivities(intent,
    
  •            intent.resolveTypeIfNeeded(mContext.getContentResolver()),
    
  •            STOCK_PM_FLAGS, userId);
    
  •        } catch (RemoteException e) {
    
  •            throw new RuntimeException("Package manager has died", e);
    
  •        }
    
  •        // get all components and the best match
    
  •        IntentFilter filter = new IntentFilter();
    
  •        filter.addAction(Intent.ACTION_MAIN);
    
  •        filter.addCategory(Intent.CATEGORY_HOME);
    
  •        filter.addCategory(Intent.CATEGORY_DEFAULT);
    
  •        final int N = list.size();
    
  •        //设置默认launcher
    
  •        ComponentName launcher = new ComponentName(packageName, className);
    
  •        ComponentName[] set = new ComponentName[N];
    
  •        ComponentName[] setLauncher = new ComponentName[2];
    
  •        int defaultMatch = 0;
    
  •        for (int i = 0; i < N; i++) {
    
  •            ResolveInfo r = list.get(i);
    
  •            set[i] = new ComponentName(r.activityInfo.packageName, r.activityInfo.name);
    
  •            Slog.d(TAG, "r.activityInfo.packageName======= " + r.activityInfo.packageName);
    
  •            Slog.d(TAG, "r.activityInfo.name========= " + r.activityInfo.name);
    
  •            //if (launcher.getClassName().equals(r.activityInfo.name)) {
    
  •            if(r.activityInfo.name.indexOf("com.android.settings.CryptKeeper") != -1) {
    
  •                     continue;
    
  •             }
    
  •           if(r.activityInfo.name.indexOf("com.android.provision.DefaultActivity") != -1) {
    
  •                   continue;
    
  •            }
    
  •             if (r.activityInfo.name.indexOf(launcher.getClassName()) != -1) {                 
    
  •             		defaultMatch = r.match;
    
  •              	setLauncher[0] = new ComponentName(r.activityInfo.packageName, r.activityInfo.name);
    
  •            } else {
    
  •                   setLauncher[1] = new ComponentName(r.activityInfo.packageName, r.activityInfo.name);
    
  •             }
    
  •        }
    
  •        Slog.w(TAG, "defaultMatch = " + defaultMatch);
    
  •        try {
    
  •            pm.addPreferredActivity(filter, defaultMatch, setLauncher, launcher, getCurrentUserIdLocked());
    
  •        } catch (RemoteException e) {
    
  •            throw new RuntimeException("Package manager has died", e);
    
  •        }
    
  •    }
    
  • }
  • private boolean hasApkInstalled(String packageName) {
  •    if (packageName == null || "".equals(packageName)) {
    
  •                   return false;
    
  •           }
    
  •    android.content.pm.ApplicationInfo info = null;
    
  •    try {
    
  •        info = mContext.getPackageManager().getApplicationInfo(packageName, 0);
    
  •       Slog.i(TAG, "packageName found " + info);
    
  •        return info != null;
    
  •    } catch (NameNotFoundException e) {
    
  •       Slog.i(TAG, "packageName not found " + packageName + " " + e);
    
  •        return false;
    
  •    }
    
  • }
  • //end
  • boolean startHomeActivityLocked(int userId, String reason) {
  •    if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
    
  •     setDefaultLauncher(userId);
    

遇到的坑
String className = “com.test.touch.homescreen.MainActivity”;
此处的className要是完整的名字,不能是.MainActivity,否则PackageManagerService会打印
Removing dangling preferred activity:xxxxxxx
1
将我们原本设置的preferred activity删除掉。

queryIntentActivities
此处query出来的launcher的activities,有多个launcher,与PackageManagerService当中识别到的launcher数量不一致,导致打印:
Result set changed, dropping preferred activity for xxxx
1
同样会删除我们之前设置的preferred activity.
所以采用了恶心的代码,删除掉其他多的activity,与PackageManagerService保持一致