概述
一、AMS启动Launcher
Launcher应用是在AMS的systemReady方法中直接调用startHomeActivityLocked启动的,下面是systemReady启动Launcher的代码。
- startHomeActivityLocked(mCurrentUserId, "systemReady");
- 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();//获取intent
- ActivityInfo aInfo =
- resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);//获取ActivityInfo
- 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) {//进程没有启动调用
- EventLog.writeEvent(EventLogTags.AM_PROC_START,"AMS -> startHomeActivityLocked startHomeActivity then startActivityLock : "+ aInfo.processName);
- intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
- mStackSupervisor.startHomeActivity(intent, aInfo, reason);
- }
- }
- return true;
- }
我们先来看看getHomeIntent这个函数。
- 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;
- }
- 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();
- }
- }
二、Launcher启动
接着我们来看下Launcher的AndroidManifest.xml,我们看下其主Activity有一个category为Android.intent.category.HOME
- <application
- android:name="com.android.launcher2.LauncherApplication"
- android:label="@string/application_name"
- android:icon="@mipmap/ic_launcher_home"
- android:hardwareAccelerated="true"
- android:largeHeap="@bool/config_largeHeap"
- android:supportsRtl="true">
- <activity
- android:name="com.android.launcher2.Launcher"
- android:launchMode="singleTask"
- android:clearTaskOnLaunch="true"
- android:stateNotNeeded="true"
- android:resumeWhilePausing="true"
- android:theme="@style/Theme"
- android:windowSoftInputMode="adjustPan"
- android:screenOrientation="nosensor">
- <intent-filter>
- <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.Java的onCreate函数中调用了mModel.startLoader函数
- protected void onCreate(Bundle savedInstanceState) {
- ......
- if (!mRestoring) {
- if (sPausedFromUserAction) {
- // If the user leaves launcher, then we should just load items asynchronously when
- // they return.
- mModel.startLoader(true, -1);
- } 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.getCurrentPage());
- }
- }
- ......
startLoader函数会post一个Runnable消息,我们来看下它的run方法
- public void startLoader(boolean isLaunching, int synchronousBindPage) {
- 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.
- 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, isLaunching);
- if (synchronousBindPage > -1 && mAllAppsLoaded && mWorkspaceLoaded) {
- mLoaderTask.runBindSynchronousPage(synchronousBindPage);
- } else {
- sWorkerThread.setPriority(Thread.NORM_PRIORITY);
- sWorker.post(mLoaderTask);
- }
- }
- }
- }
在它的run方法中会调用loadAndBindAllApps函数,在loadAndBindAllApps函数中又会调用loadAllAppsByBatch函数
- public void run() {
- synchronized (mLock) {
- mIsLoaderTaskRunning = true;
- }
- final Callbacks cbk = mCallbacks.get();
- final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true;
- keep_running: {
- // Elevate priority when Home launches for the first time to avoid
- // starving at boot time. Staring at a blank home is not cool.
- synchronized (mLock) {
- if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +
- (mIsLaunching ? "DEFAULT" : "BACKGROUND"));
- Process.setThreadPriority(mIsLaunching
- ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
- }
- // First step. Load workspace first, this is necessary since adding of apps from
- // managed profile in all apps is deferred until onResume. See http://b/17336902.
- if (loadWorkspaceFirst) {
- if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
- loadAndBindWorkspace();
- } else {
- Log.d(TAG, "step 1: special: loading all apps");
- loadAndBindAllApps();
- }
我们先来看下loadAndBindAllApps函数,这个函数先进入while循环,然后调用了LauncherApps的getActivityList函数,后面又会调用callbacks的bindAllApplications
- private void loadAllAppsByBatch() {
- final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- ......
- mBgAllAppsList.clear();
- final int profileCount = profiles.size();
- for (int p = 0; p < profileCount; p++) {
- ......
- while (i < N && !mStopped) {
- if (i == 0) {
- final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- apps = mLauncherApps.getActivityList(null, user);
- ......
- mHandler.post(new Runnable() {
- public void run() {
- final long t = SystemClock.uptimeMillis();
- if (callbacks != null) {
- if (firstProfile) {
- callbacks.bindAllApplications(added);
- } else {
- callbacks.bindAppsAdded(added);
- }
- if (DEBUG_LOADERS) {
- Log.d(TAG, "bound " + added.size() + " apps in "
- + (SystemClock.uptimeMillis() - t) + "ms");
- }
- } else {
- Log.i(TAG, "not binding apps: no Launcher activity");
- }
- }
- });
- ......
我们先来看LauncherApps的getActivityList函数,它先用mService成员变量调用getLauncherActivities函数获取到list<ResolveInfo>,然后封装在ArrayList<LauncherActivityInfo> 中。
- public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
- List<ResolveInfo> activities = null;
- try {
- activities = mService.getLauncherActivities(packageName, user);
- } catch (RemoteException re) {
- throw new RuntimeException("Failed to call LauncherAppsService");
- }
- if (activities == null) {
- return Collections.EMPTY_LIST;
- }
- ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>();
- final int count = activities.size();
- for (int i = 0; i < count; i++) {
- ResolveInfo ri = activities.get(i);
- long firstInstallTime = 0;
- try {
- firstInstallTime = mPm.getPackageInfo(ri.activityInfo.packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime;
- } catch (NameNotFoundException nnfe) {
- // Sorry, can't find package
- }
- LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user,
- firstInstallTime);
- if (DEBUG) {
- Log.v(TAG, "Returning activity for profile " + user + " : "
- + lai.getComponentName());
- }
- lais.add(lai);
- }
- return lais;
- }
其service是class LauncherAppsImpl extends ILauncherApps.Stub 下面是getLauncherActivities函数,肯定也是通过PKMS来获取相关Activity的ResolveInfo的。
- @Override
- public List<ResolveInfo> getLauncherActivities(String packageName, UserHandle user)
- throws RemoteException {
- ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
- if (!isUserEnabled(user)) {
- return new ArrayList<ResolveInfo>();
- }
- final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- mainIntent.setPackage(packageName);
- long ident = Binder.clearCallingIdentity();
- try {
- List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0 /* flags */,
- user.getIdentifier());
- return apps;
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
最后回调Launcher.java的bindAllApplications函数,最后在这个函数中可以在桌面上展示系统中所有的应用程序了。
- public void bindAllApplications(final ArrayList<ApplicationInfo> apps) {
- Runnable setAllAppsRunnable = new Runnable() {
- public void run() {
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.setApps(apps);
- }
- }
- };
- // Remove the progress bar entirely; we could also make it GONE
- // but better to remove it since we know it's not going to be used
- View progressBar = mAppsCustomizeTabHost.
- findViewById(R.id.apps_customize_progress_bar);
- if (progressBar != null) {
- ((ViewGroup)progressBar.getParent()).removeView(progressBar);
- // We just post the call to setApps so the user sees the progress bar
- // disappear-- otherwise, it just looks like the progress bar froze
- // which doesn't look great
- mAppsCustomizeTabHost.post(setAllAppsRunnable);
- } else {
- // If we did not initialize the spinner in onCreate, then we can directly set the
- // list of applications without waiting for any progress bars views to be hidden.
- setAllAppsRunnable.run();
- }
- }
三、显示应用图标
我们再来看下Launcher的onClick函数,当调用showWorkspace可以显示所有应用的图标。
- public void onClick(View v) {
- // Make sure that rogue clicks don't get through while allapps is launching, or after the
- // view has detached (it's possible for this to happen if the view is removed mid touch).
- if (v.getWindowToken() == null) {
- return;
- }
- if (!mWorkspace.isFinishedSwitchingState()) {
- return;
- }
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- // Open shortcut
- final Intent intent = ((ShortcutInfo) tag).intent;
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- intent.setSourceBounds(new Rect(pos[0], pos[1],
- pos[0] + v.getWidth(), pos[1] + v.getHeight()));
- boolean success = startActivitySafely(v, intent, tag);
- if (success && v instanceof BubbleTextView) {
- mWaitingForResume = (BubbleTextView) v;
- mWaitingForResume.setStayPressed(true);
- }
- } else if (tag instanceof FolderInfo) {
- if (v instanceof FolderIcon) {
- FolderIcon fi = (FolderIcon) v;
- handleFolderClick(fi);
- }
- } else if (v == mAllAppsButton) {
- if (isAllAppsVisible()) {
- showWorkspace(true);
- } else {
- onClickAllAppsButton(v);
- }
- }
- }
在showWorkspace中会显示所有的图标
- void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
- if (mState != State.WORKSPACE) {
- boolean wasInSpringLoadedMode = (mState == State.APPS_CUSTOMIZE_SPRING_LOADED);
- mWorkspace.setVisibility(View.VISIBLE);
- hideAppsCustomizeHelper(State.WORKSPACE, animated, false, onCompleteRunnable);
- // Show the search bar (only animate if we were showing the drop target bar in spring
- // loaded mode)
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.showSearchBar(wasInSpringLoadedMode);
- }
- // We only need to animate in the dock divider if we're going from spring loaded mode
- showDockDivider(animated && wasInSpringLoadedMode);
- // Set focus to the AppsCustomize button
- if (mAllAppsButton != null) {
- mAllAppsButton.requestFocus();
- }
- }
- mWorkspace.flashScrollingIndicator(animated);
- // Change the state *after* we've called all the transition code
- mState = State.WORKSPACE;
- // Resume the auto-advance of widgets
- mUserPresent = true;
- updateRunning();
- // Send an accessibility event to announce the context change
- getWindow().getDecorView()
- .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- }
而点击应用图标,最终会调用Launcher.java的startActivitySafely来启动应用。这里调用的startActivity就是Activity的startActivity函数。
- boolean startActivitySafely(View v, Intent intent, Object tag) {
- boolean success = 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;
- }
最后
以上就是超帅玉米为你收集整理的Android Launcher2启动分析的全部内容,希望文章能够帮你解决Android Launcher2启动分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复