Android系統開發-選擇並啓動默認Launcher

若是在Android設備上又安裝了一個Launcher應用,當咱們返回主頁的時候,Android就會彈出一個彈窗,要用戶 選擇要啓動的Launcher應用,以下圖所示:java

這個是普通Android設備的正常流程,如今咱們的需求是再也不顯示這個提示窗,在設置中增長一個選擇默認啓動Launcher的頁面,默認選擇Launcher3。android

Settings

在設置中增長一個這樣的頁面,顯示全部聲明瞭"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.javaorm

在這裏就不具體分析源碼了,就看關鍵部分對象

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

相關文章
相關標籤/搜索