Android6.0 Launcher2应用解析

Android6.0 Launcher2应用解析,第1张

概述在之前我们分析了Android6.0系统在启动时安装应用程序的过程,这些应用程序安装好之后,Launcher应用就负责把它们在桌面上展示出来。

在之前我们分析了AndroID6.0系统在启动时安装应用程序的过程,这些应用程序安装好之后,Launcher应用就负责把它们在桌面上展示出来。

一、AMS启动Launcher 

Launcher应用是在AMS的systemReady方法中直接调用startHomeActivityLocked启动的,下面是systemReady启动Launcher的代码。 

startHomeActivityLocked(mCurrentUserID,"systemReady");我们来看下这个函数,先调用了getHomeIntent方法来获取Intent,然后也是调用resolveActivityInfo函数从PKMS获取ActivityInfo,接着当进程没有启动的话,调用ActivityStackSupervisor的startHomeActivity函数

   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;  }

然后我们来看下ActivityStackSupervisor的startHomeActivity函数,它也是调用了startActivityLocked来启动Activity的,在之前的博客分析过这个函数这里我们就不介绍了。

   voID startHomeActivity(Intent intent,ActivityInfo aInfo,String reason) {    moveHomeStackTaskTotop(HOME_ACTIVITY_TYPE,reason);    startActivityLocked(null /* caller */,intent,null /* resolvedType */,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,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,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;  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android6.0 Launcher2应用解析全部内容,希望文章能够帮你解决Android6.0 Launcher2应用解析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1148111.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存