在工作中有时候会开发定制的启动器,然后每次都要按home键选择定制启动器后再按一下才能选择始终,这样一个是比较麻烦,另一个是不想用户自行控制,所以需要代码来设置默认桌面。
找到系统设置默认桌面位置,跟踪代码调用
跟踪这个界面的代码发现设置是在这里 DefaultHomePicker.java这个文件里面,其实就是调用packageManage的replacePreferredActivity方法。
protected boolean setDefaultKey(String key) {
if (!TextUtils.isEmpty(key)) {
final ComponentName component = ComponentName.unflattenFromString(key);
final List<ResolveInfo> homeActivities = new ArrayList<>();
mPm.getHomeActivities(homeActivities);
final List<ComponentName> allComponents = new ArrayList<>();
for (ResolveInfo info : homeActivities) {
final ActivityInfo appInfo = info.activityInfo;
ComponentName activityName = new ComponentName(appInfo.packageName, appInfo.name);
allComponents.add(activityName);
}
mPm.replacePreferredActivity(
DefaultHomePreferenceController.HOME_FILTER,
IntentFilter.MATCH_CATEGORY_EMPTY,
allComponents.toArray(new ComponentName[0]),
component);
// Launch the new Home app so the change is immediately visible even if
// the Home button is not pressed.
final Context context = getContext();
Intent i = new Intent(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_HOME);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
return true;
}
return false;
}
这里用到的方法是隐藏的,所以我们反射调用,如下
public void setDefaultLauncherApp(ComponentName componentName) {
PackageManager packageManager = mContext.getPackageManager();
Class<?> refPackageManager = packageManager.getClass();
Method[] methods = refPackageManager.getDeclaredMethods();
Method mReplacePreferredActivity = null;
Method mGetHomeActivities = null;
for (Method method : methods) {
if (method.getName().equals("replacePreferredActivity")) {
mReplacePreferredActivity = method;
}
if (method.getName().equals("getHomeActivities")) {
mGetHomeActivities = method;
}
}
mReplacePreferredActivity.setAccessible(true);
mGetHomeActivities.setAccessible(true);
IntentFilter HOME_FILTER = new IntentFilter(Intent.ACTION_MAIN);
HOME_FILTER.addCategory(Intent.CATEGORY_HOME);
HOME_FILTER.addCategory(Intent.CATEGORY_DEFAULT);
final List<ComponentName> allComponents = new ArrayList<>();
final List<ResolveInfo> homeActivities = new ArrayList<>();
try {
mGetHomeActivities.invoke(packageManager, homeActivities);
for (ResolveInfo info : homeActivities) {
final ActivityInfo appInfo = info.activityInfo;
ComponentName activityName = new ComponentName(appInfo.packageName, appInfo.name);
allComponents.add(activityName);
}
mReplacePreferredActivity.invoke(packageManager, HOME_FILTER, IntentFilter.MATCH_CATEGORY_EMPTY, allComponents.toArray(new ComponentName[0]), componentName);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
至于为什么要用这种反射方法去找到对应的方法而不是用方法名直接get出来,这个原因之前的文章有讲过,是有时候直接提提不出来,用遍历方法的方式这时候根据方法名去找对应的方法。
这个方法里面传的是ComponentName 这个就是需要设置的启动器的包名和启动的activity名,如果这个activity没有加home标签的话,那会设置不成功。
并且需要系统权限(系统签名)才能调用这个,请注意以上代码基于Android P,不保证之前和之后版本能用
以上。