背景:需要实现使用自定的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界面。
如有不当之处,还请同学们指正~
网友评论