美文网首页
Android framework 使用自定的activity取

Android framework 使用自定的activity取

作者: 最忆是深秋 | 来源:发表于2018-05-04 13:52 被阅读266次

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

    1.先看一下launcher的流程

    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

           <activity
                android:name="com.test.learning.MainActivity"
                android:launchMode="singleInstance"
                android:excludeFromRecents="true"
                android:configChanges="mcc|mnc"
                android:screenOrientation="portrait"
                android:exported="true">
                <intent-filter android:priority="1">
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.HOME"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <category android:name="android.intent.category.MONKEY"/>
                </intent-filter>
            </activity>
    

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

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


    image
    private void adjustPriority(
                    List<PackageParser.Activity> 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取

          本文链接:https://www.haomeiwen.com/subject/mesdrftx.html