Android framework 使用自定的activity取代默认的Launcher界面

背景:需要实现使用自定的activity取代默认的Launcher界面
a. 开机启动后进入自定义的activity
b. 按home键跳转到自定义的activity

1.先看一下launcher的流程

Android framework 使用自定的activity取代默认的Launcher界面_第1张图片
image
    boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            // We are running in factory test mode, but unable to find
            // the factory test app, so just sit around displaying the
            // error message and don't try to start anything.
            return false;
        }
        Intent intent = getHomeIntent();
        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
            // Don't do this if the home app is currently being
            // instrumented.
            aInfo = new ActivityInfo(aInfo);
            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
            if (app == null || app.instrumentationClass == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }
        return true;
    }
//startHomeActivityLocked中将“launcher”启动起来,打个引号就是说不一定是launcher应用,可以是其他符合条件的组件。


String mTopAction = Intent.ACTION_MAIN;
Intent getHomeIntent() {
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);
        }
        return intent;
 }
 //创建一个 ACTION_MAIN 并且CATEGORY_HOME 类型的 Intent ,通过resolveActivityInfo函数向 PackageManagerService 查询 CATEGORY 是否类型为 HOME 并且ACTION为ACTION_MAIN 的应用
 //startHomeActivityLocked中resolveActivityInfo方法会返回一个最佳匹配的组件。这个处理是在PMS中完成的,当有多个组件action和category都满足条件的情况下,
 //会依据priority的值的大小来选择,取priority值最大的一个,当有多个组件priority相同的情况,会提示用户进行选择.

2. 那么我们就构造这样一个activity

       
            
                
                
                
                
            
        

根据第一小节launcher启动流程的描述,定义了这样一个activity后,满足了action.MAIN,category.HOME,priority=”1”(launcher为0,默认的),应该就可以替代launcher了吧,然而并没有什么卵用。

通过加log发现resolveActivityInfo方法返回的最佳匹配组件还是launcher界面。明明已经定义了我们这个activity priority=”1”了呀
这是因为PMS在解析所有组件的时候会根据策略调整intent的优先级,具体策略在PMS的adjustPriority方法中。(大于0的会被强制设置为0)
这一块的部分流程参加下图:


Android framework 使用自定的activity取代默认的Launcher界面_第2张图片
image
private void adjustPriority(
                List systemActivities, ActivityIntentInfo intent) {
            // nothing to do; priority is fine as-is
            if (intent.getPriority() <= 0) {
                return;
            }

            final ActivityInfo activityInfo = intent.activity.info;
            final ApplicationInfo applicationInfo = activityInfo.applicationInfo;

            if("your pacakgename".equals(applicationInfo.packageName)
                    && "your activity classname".equals(intent.activity.className)) {
                return;
            }
            ..................
            ..................
}

在adjustPriority方法中过滤掉我们自定义的activity ,不让framework去强制设置成0.
至此,开机启动的首个activity就是我们自定义的activity界面,按home键进入的也是我们自定义的activity界面。

如有不当之处,还请同学们指正~

你可能感兴趣的:(Android framework 使用自定的activity取代默认的Launcher界面)