若是在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,功能實現完成,自測也沒有問題。