背景:需要實(shí)現(xiàn)使用自定的activity取代默認(rèn)的Launcher界面
a. 開機(jī)啟動(dòng)后進(jìn)入自定義的activity
b. 按home鍵跳轉(zhuǎn)到自定義的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中將“l(fā)auncher”啟動(dòng)起來,打個(gè)引號(hào)就是說不一定是launcher應(yīng)用师脂,可以是其他符合條件的組件害晦。
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;
}
//創(chuàng)建一個(gè) ACTION_MAIN 并且CATEGORY_HOME 類型的 Intent ,通過resolveActivityInfo函數(shù)向 PackageManagerService 查詢 CATEGORY 是否類型為 HOME 并且ACTION為ACTION_MAIN 的應(yīng)用
//startHomeActivityLocked中resolveActivityInfo方法會(huì)返回一個(gè)最佳匹配的組件获搏。這個(gè)處理是在PMS中完成的谓罗,當(dāng)有多個(gè)組件action和category都滿足條件的情況下刑巧,
//會(huì)依據(jù)priority的值的大小來選擇,取priority值最大的一個(gè)秀菱,當(dāng)有多個(gè)組件priority相同的情況部凑,會(huì)提示用戶進(jìn)行選擇.
2. 那么我們就構(gòu)造這樣一個(gè)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>
根據(jù)第一小節(jié)launcher啟動(dòng)流程的描述,定義了這樣一個(gè)activity后车海,滿足了action.MAIN笛园,category.HOME,priority=”1”(launcher為0侍芝,默認(rèn)的)研铆,應(yīng)該就可以替代launcher了吧,然而并沒有什么卵用州叠。
通過加log發(fā)現(xiàn)resolveActivityInfo方法返回的最佳匹配組件還是launcher界面蚜印。明明已經(jīng)定義了我們這個(gè)activity priority=”1”了呀
這是因?yàn)镻MS在解析所有組件的時(shí)候會(huì)根據(jù)策略調(diào)整intent的優(yōu)先級(jí),具體策略在PMS的adjustPriority方法中留量。(大于0的會(huì)被強(qiáng)制設(shè)置為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去強(qiáng)制設(shè)置成0.
至此,開機(jī)啟動(dòng)的首個(gè)activity就是我們自定義的activity界面楼熄,按home鍵進(jìn)入的也是我們自定義的activity界面忆绰。
如有不當(dāng)之處,還請(qǐng)同學(xué)們指正~