若是在Android设备上又安装了一个Launcher应用,当咱们返回主页的时候,Android就会弹出一个弹窗,要用户 选择要启动的Launcher应用,以下图所示:java
这个是普通Android设备的正常流程,如今咱们的需求是再也不显示这个提示窗,在设置中增长一个选择默认启动Launcher的页面,默认选择Launcher3。android
在设置中增长一个这样的页面,显示全部声明了"android.intent.category.HOME"
的应用markdown
private fun getAllLauncherApps(): MutableList<AppInfo> {
val list = ArrayList<AppInfo>()
val launchIntent = Intent(Intent.ACTION_MAIN, null)
.addCategory(Intent.CATEGORY_HOME)
val intents = packageManager.queryIntentActivities(launchIntent, 0)
//遍历
for (ri in intents) {
//获得包名
val packageName = ri.activityInfo.applicationInfo.packageName
if (packageName == "com.android.settings") { //不显示原生设置
continue
}
//获得图标
val icon = ri.loadIcon(packageManager)
//获得应用名称
val appName = ri.loadLabel(packageManager).toString()
//封装应用信息对象
val appInfo = AppInfo(icon, appName, packageName)
//添加到list
list.add(appInfo)
}
return list
}
复制代码
使用PackageManager提供的queryIntentActivities方法就能够获取全部Launcher应用,原生设置中也有Activity声明了HOME属性,在这里就把它屏蔽掉。app
默认选择Launcher3应用为默认启动函数
private val DEFAULT_LAUNCHER = "my_default_launcher"
defaultLauncher = Settings.Global.getString(contentResolver, DEFAULT_LAUNCHER)
if (defaultLauncher.isNullOrEmpty()) {
defaultLauncher = "com.android.launcher3"
Settings.Global.putString(contentResolver, DEFAULT_LAUNCHER, defaultLauncher)
}
复制代码
当选择另外一个应用,就把选择应用的包名设置到 Settings.Global中。this
这样应用选择页面完成,也设置了一个全局的参数提供给系统。spa
最开始提到了Launcher选择弹窗,咱们就考虑在这里作点事,把弹窗的逻辑给跳过,就能够实现默认启动。code
弹窗源码位于frameworks/base/core/java/com/android/internal/app/ResolverActivity.java
orm
在这里就不具体分析源码了,就看关键部分对象
public boolean configureContentView(List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, boolean alwaysUseOption) {
// The last argument of createAdapter is whether to do special handling
// of the last used choice to highlight it in the list. We need to always
// turn this off when running under voice interaction, since it results in
// a more complicated UI that the current voice interaction flow is not able
// to handle.
mAdapter = createAdapter(this, payloadIntents, initialIntents, rList,
mLaunchedFromUid, alwaysUseOption && !isVoiceInteraction());
final int layoutId;
if (mAdapter.hasFilteredItem()) {
layoutId = R.layout.resolver_list_with_default;
alwaysUseOption = false;
} else {
layoutId = getLayoutResource();
}
mAlwaysUseOption = alwaysUseOption;
int count = mAdapter.getUnfilteredCount();
if (count == 1 && mAdapter.getOtherProfile() == null) {
// Only one target, so we're a candidate to auto-launch!
final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
if (shouldAutoLaunchSingleChoice(target)) {
safelyStartActivity(target);
mPackageMonitor.unregister();
mRegistered = false;
finish();
return true;
}
}
if (count > 0) {
// add by liuwei,if set my_default_launcher,start default
String defaultlauncher = Settings.Global.getString(this.getContentResolver(), "my_default_launcher");
final TargetInfo defaultTarget = mAdapter.targetInfoForDefault(defaultlauncher);
if(defaultTarget != null){
safelyStartActivity(defaultTarget);
mPackageMonitor.unregister();
mRegistered = false;
finish();
return true;
}
//end
setContentView(layoutId);
mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
onPrepareAdapterView(mAdapterView, mAdapter, alwaysUseOption);
} else {
setContentView(R.layout.resolver_list);
final TextView empty = (TextView) findViewById(R.id.empty);
empty.setVisibility(View.VISIBLE);
mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
mAdapterView.setVisibility(View.GONE);
}
return false;
}
复制代码
在configureContentView中判断launcher应用个数,若是为1,则直接启动,finish当前页面。下面判断count>0,咱们就在这里面增长本身的逻辑,获取配置的Settings.Global参数,再去Adapter中判断是否有应用包名和参数匹配,若是有就safelyStartActivity(),关闭弹窗。若是没有匹配包名,就走正常流程,弹窗提示用户。
mAdapter.targetInfoForDefault函数是在 public class ResolveListAdapter extends BaseAdapter
中增长函数
public TargetInfo targetInfoForDefault(String myDefault){
if(myDefault == null){
return null;
}
TargetInfo info = null;
for(int i=0;i<mDisplayList.size();i++){
String disPackageName = mDisplayList.get(i).getResolveInfo().activityInfo.applicationInfo.packageName;
if(myDefault.equals(disPackageName) ){
info = mDisplayList.get(i);
break;
}
}
return info;
}
复制代码
OK,功能实现完成,自测也没有问题。