背景:需要实现使用自定的activity取代默认的Launcher界面 a. 开机启动后进入自定义的activity b. 按home键跳转到自定义的activity
1.先看一下launcher 的启动流程:
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) 这一块的部分流程参加下图:
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界面。
如有不当之处,还请同学们指正~