Android如何设置默认的Launcher
问题
机器装有多个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保持一致
相关文章
- Android 隐藏EditText的焦点
- [Android] 拍照、截图、保存并显示在ImageView控件中
- android 中如何分析内存泄漏
- JAVA Eclipse开发Android如何设置滚动条最大值最小值
- JAVA Eclipse创建的Android程序如何不显示标题栏
- Android API之android.widget.Filterable
- 如何在使用eclipse的情况下,清理android项目中的冗余class文件和资源文件以及冗余图片
- 如何使用Android中的OpenGL ES媒体效果
- 《Android进阶之光》--多线程编程
- 转--Android如何在java代码中设置margin
- Illegal resource reference: @*android resources are private and not always present
- Android开发者指南(9) —— ProGuard
- 中年程序员只有几年Android开发经验,该如何保持在公司的核心竞争力?
- Android SlidingMenu导致虚拟键盘位置有黑灰空白
- Android 8.1 如何动态修改devnull权限组
- Android 10 如何在SurfaceFlinger中解决按Power键会从横屏切换到竖屏问题
- Android 4.4 系统如何恢复出厂设置
- Android 如何设置背景图片
- Android RecyclerView根据不同的item设置不同的背景颜色
- 【Android笔记50】Android应用如何获取系统服务(软键盘管理器、闹钟管理器)
- Android中的RAM、ROM、SD卡以及各种内存的区别
- Android studio的logcat窗口被拖出来后如何还原
- Android中如何在代码中设置View的宽和高?
- Android 如何从应用返回待机界面(HOME)
- Android里获取正在前端运行的Activity的包名