Android如何设置默认的Launcher

本文介绍如何在Android系统中通过修改ActivityManagerService和PackageManagerService代码,设置特定应用为默认Launcher,避免首次开机时出现选择Launcher的对话框。涉及XML配置、Intent过滤及组件匹配,确保设置的Launcher成为首选。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

机器装有多个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 

将我们原本设置的preferred activity删除掉。

  • queryIntentActivities
    此处query出来的launcher的activities,有多个launcher,与PackageManagerService当中识别到的launcher数量不一致,导致打印:
Result set changed, dropping preferred activity for xxxx

同样会删除我们之前设置的preferred activity.
所以采用了恶心的代码,删除掉其他多的activity,与PackageManagerService保持一致

参考网页

https://blog.youkuaiyun.com/lancelots/article/details/82985971

Android设备的默认launcher设置是指系统默认的启动器(Launcher)应用程序。启动器是用户在设备上看到和操作的主屏幕,它提供了桌面、应用程序列表、小部件和壁纸等功能。 在Android设备上,不同的制造商可能会有不同的默认启动器设置,例如Samsung可能会有自己的启动器样式,而Google的Pixel设备则使用原生的Android启动器。 默认启动器有以下几个主要特点和功能: 1. 桌面:默认启动器会在设备主屏幕上显示桌面,用户可以在桌面上添加和管理应用程序、小部件和快捷方式等。 2. 应用程序列表:用户可以通过默认启动器访问设备上安装的所有应用程序的列表,并进行搜索和排序。 3. 小部件:默认启动器支持用户在桌面上添加各种小部件,例如天气、日历、音乐播放器等,以便用户更方便地获取相关信息。 4. 壁纸:默认启动器还允许用户更改桌面背景壁纸,可以选择自己喜欢的图片或者使用系统提供的预设壁纸。 对于用户来说,选择适合自己的默认启动器可以增加使用Android设备的个性化和便利性。用户可以根据自己的需求和偏好,选择不同功能和样式的启动器来进行设置。有些启动器还提供了更多的自定义选项,例如主题、图标包等,使用户能够将设备界面个性化到自己喜欢的样子。 总之,Android设备的默认启动器设置是一个重要的用户体验方面的设置选项,通过它可以实现设备主屏幕的个性化和功能拓展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值