Launcher的启动
手机开机的时候启动systemservice,systemservice启动ActivityManagerService,PMS等,启动Launcher首先分析ActivityManagerService
代码具体实现:
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);
mStackSupervisor.startHomeActivity(intent, aInfo, reason);
}
}
return true;
}
startHomeActivityLocked方法首先通过调用getHomeIntent()方法来构建一个CATEGORY_HOME类型的intent,然后调用PackageManagerService的resolveActivityInfo()方法来查询category类型为HOME的Activity,然后调用getProcessRecordLocked()方法获得Activity的进程信息,由于是第一次启动Activity,Activity代表的进程还没有启动,所以这里返回的ProcessRecord为null,接下来调用mStackSupervisor对象的startHomeActivity()方法启动Launcher,而mStackSupervisor是一个ActivityStackSupervisor类型的对象,接下来看一下getHomeIntent方法怎么构建一个CATEGORY_HOME类型的intent
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}
getHomeIntent方法通过addCategory方法添加一个CATEGORY_HOME类型的Intent,并返回
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
startActivityLocked(null /* caller */, intent, null /* resolvedType */, aInfo,
null /* voiceSession */, null /* voiceInteractor */, null /* resultTo */,
null /* resultWho */, 0 /* requestCode */, 0 /* callingPid */, 0 /* callingUid */,
null /* callingPackage */, 0 /* realCallingPid */, 0 /* realCallingUid */,
0 /* startFlags */, null /* options */, false /* ignoreTargetSecurity */,
false /* componentSpecified */,
null /* outActivity */, null /* container */, null /* inTask */);
if (inResumeTopActivity) {
// If we are in resume section already, home activity will be initialized, but not
// resumed (to avoid recursive resume) and will stay that way until something pokes it
// again. We need to schedule another resume.
scheduleResumeTopActivities();
}
}
startHomeActivity方法中调用moveHomeStackTaskToTop()方法把Launcher放进HomeStack里,Stack分为2种:
Stack #0 专门放Launcher和SystemUI
Stack #1 放其他应用程序
回到startHomeActivity方法中,然后调用startActivityLocked方法去真正的启动Launcher这个Activity,这个启动很复杂,这里只要知道,startActivityLocked方法会把Launcher这个activity启动起来,当Activity启动之后,就会进入它的onCreate方法中,因此,接下来看Launcher的onCreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
...
super.onCreate(savedInstanceState);
initializeDynamicGrid(false);
...
setContentView(R.layout.launcher);
if (!mRestoring) {
if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
// If the user leaves launcher, then we should just load items asynchronously when
// they return.
mModel.startLoader(true, PagedView.INVALID_RESTORE_PAGE);
} else {
// We only load the page synchronously if the user rotates (or triggers a
// configuration change) while launcher is in the foreground
mModel.startLoader(true, mWorkspace.getRestorePage());
}
}
....
}
onCreate方法中做了一些与UI有关的操作,这里主要关心在Launcher里面加载应用图标操作,即把安装的所有的应用图标加载到桌面上,当点击某个应用图标的时候,就会启动这个应用程序,此处通过调用mModel对象的startLoader方法来进一步处理
public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {
synchronized (mLock) {
if (DEBUG_LOADERS) {
Log.d(TAG, "startLoader isLaunching=" + isLaunching);
}
// Clear any deferred bind-runnables from the synchronized load process
// We must do this before any loading/binding is scheduled below.
synchronized (mDeferredBindRunnables) {
mDeferredBindRunnables.clear();
}
// Don't bother to start the thread if we know it's not going to do anything
if (mCallbacks != null && mCallbacks.get() != null) {
// If there is already one running, tell it to stop.
// also, don't downgrade isLaunching if we're already running
isLaunching = isLaunching || stopLoaderLocked();
mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);
if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
&& mAllAppsLoaded && mWorkspaceLoaded) {
mLoaderTask.runBindSynchronousPage(synchronousBindPage);
} else {
sWorkerThread.setPriority(Thread.NORM_PRIORITY);
sWorker.post(mLoaderTask);
}
}
}
}
startLoader方法中new了一个LoaderTask,LoaderTask实现了Runnable,先到run方法中去看一下
public void run() {
...
isUpgrade = loadAndBindWorkspace();
....
loadAndBindAllApps();
}
run方法首先调用loadAndBindWorkspace加载workspace,然后调用loadAndBindAllApps方法加载应用程序图标
private void loadAndBindAllApps() {
if (DEBUG_LOADERS) {
Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
}
if (!mAllAppsLoaded) {
loadAllApps();
synchronized (LoaderTask.this) {
if (mStopped) {
return;
}
mAllAppsLoaded = true;
}
} else {
onlyBindAllApps();
}
}
loadAndBindAllApps方法中调用了loadAllApps方法继续处理
private void loadAllApps() {
....
// Post callback on main thread
mHandler.post(new Runnable() {
public void run() {
final long bindTime = SystemClock.uptimeMillis();
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindAllApplications(added);
if (DEBUG_LOADERS) {
Log.d(TAG, "bound " + added.size() + " apps in "
+ (SystemClock.uptimeMillis() - bindTime) + "ms");
}
} else {
Log.i(TAG, "not binding apps: no Launcher activity");
}
}
});
}
loadAllApps方法中回调了bindAllApplications方法
public void bindAllApplications(final ArrayList<AppInfo> apps) {
if (LauncherAppState.isDisableAllApps()) {
if (mIntentsOnWorkspaceFromUpgradePath != null) {
if (LauncherModel.UPGRADE_USE_MORE_APPS_FOLDER) {
getHotseat().addAllAppsFolder(mIconCache, apps,
mIntentsOnWorkspaceFromUpgradePath, Launcher.this, mWorkspace);
}
mIntentsOnWorkspaceFromUpgradePath = null;
}
if (mAppsCustomizeContent != null) {
mAppsCustomizeContent.onPackagesUpdated(
LauncherModel.getSortedWidgetsAndShortcuts(this));
}
} else {
if (mAppDrawerAdapter != null) {
mAppDrawerAdapter.setApps(apps);
}
if (mAppsCustomizeContent != null) {
mAppsCustomizeContent.setApps(apps);
mAppsCustomizeContent.onPackagesUpdated(
LauncherModel.getSortedWidgetsAndShortcuts(this));
}
}
}
到这里Launcher的启动和加载应用图标就介绍完了,当点击某个图标的时候,怎么启动应用程序呢
public boolean startActivitySafely(View v, Intent intent, Object tag) {
boolean success = false;
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
}
for (int i = 0; i < TRIGGER_INTENT.length; i++) {
if (intent.getAction().equals(TRIGGER_INTENT[i])) {
final String requiredPermission = REQUIRED_PERMISSIONS[i];
int hasCallPhonePermission = ContextCompat.checkSelfPermission(Launcher.this,
requiredPermission);
if (hasCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
mPermissionIntent = intent;
mPermissionTag = tag;
mPermissionView = v;
if (!ActivityCompat.shouldShowRequestPermissionRationale(Launcher.this,
requiredPermission)) {
String message = getString(R.string.no_permission_hint) +
getString(ACCESS_PERMISSION_HINT[i]);
showMessageOKCancel(message,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(Launcher.this,
new String[]{requiredPermission},
REQUEST_CODE_ASK_PERMISSIONS);
}
});
return false;
}
ActivityCompat.requestPermissions(Launcher.this,
new String[]{requiredPermission},
REQUEST_CODE_ASK_PERMISSIONS);
return false;
}
}
}
try {
success = startActivity(v, intent, tag);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
}
return success;
}
当点击某个应用图标时,就会通过调用startActivity方法来把对应的Activity启动起来