android 6.0 icon,Android6.0 Launcher2应用解析

在之前我们分析了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 */, 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

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">

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">

......

在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,然后封装在ArrayList 中。

public List getActivityList(String packageName, UserHandle user) {

List 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 lais = new ArrayList();

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 getLauncherActivities(String packageName, UserHandle user)

throws RemoteException {

ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);

if (!isUserEnabled(user)) {

return new ArrayList();

}

final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);

mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

mainIntent.setPackage(packageName);

long ident = Binder.clearCallingIdentity();

try {

List apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0 /* flags */,

user.getIdentifier());

return apps;

} finally {

Binder.restoreCallingIdentity(ident);

}

}

最后回调Launcher.java的bindAllApplications函数,最后在这个函数中可以在桌面上展示系统中所有的应用程序了。

public void bindAllApplications(final ArrayList 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;

}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值