相信大家都用过任务管理器,不同的手机上面启动的方式可能会有不同,有虚拟按键或者实体按键的,可能会通过短按或者长按Menu键来触发,如果这些都没有,只有一个指纹按键的,可能是通过长按的方式来触发。这个功能我们经常会用到,他可以让我们快速回到之前任务栈,好了,废话不多说了,直接来分析代码。
我们分为五个部分来讲解,分别是:
文件:PhoneStatusBar.java
private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
awakenDreams();
// 见1.1
toggleRecentApps();
}
};
文件:BaseStatusBar.java
@Override
public void toggleRecentApps() {
// 见1.1.1
toggleRecents();
}
文件:BaseStatusBar.java
protected void toggleRecents() {
if (mRecents != null) {
// 见1.2
mRecents.toggleRecents(mDisplay);
}
}
文件:Recents.java
@Override
public void toggleRecents(Display display) {
......
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
// 见1.2.1
mImpl.toggleRecents(growTarget);
} else {
......
}
}
这个方法的从名字也能看出来是要启动Recents activity,主要通过RecentsImpl的toggleRecents方法,我们继续往下看
文件:RecentsImpl.java
public void toggleRecents(int growTarget) {
// Skip this toggle if we are already waiting to trigger recents via alt-tab
if (mFastAltTabTrigger.isDozing()) {
return;
}
mDraggingInRecents = false;
mLaunchedWhileDocking = false;
mTriggeredFromAltTab = false;
try {
SystemServicesProxy ssp = Recents.getSystemServices();
MutableBoolean isHomeStackVisible = new MutableBoolean(true);
long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
if (ssp.isRecentsActivityVisible(isHomeStackVisible)) {
......
} else {
// 间隔的时间要大于350
if (elapsedTime < MIN_TOGGLE_DELAY_MS) {
return;
}
// 获得正在运行的任务栈
ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
// 见1.2.2
startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */,
growTarget);
// Only close the other system windows if we are actually showing recents
ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
mLastToggleTime = SystemClock.elapsedRealtime();
}
} catch (ActivityNotFoundException e) {
Log.e(TAG, "Failed to launch RecentsActivity", e);
}
}
这里最重要的就是startRecentsActivity,也就是启动任务管理器的Acitvity
文件:RecentsImpl.java
protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
boolean isHomeStackVisible, boolean animate, int growTarget) {
......
// animate为true
if (!animate) {
startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1));
return;
}
ActivityOptions opts;
if (isBlacklisted) {
opts = getUnknownTransitionActivityOptions();
} else if (useThumbnailTransition) {
// Try starting with a thumbnail transition
opts = getThumbnailTransitionActivityOptions(runningTask, mDummyStackView,
windowOverrideRect);
} else {
// 当栈的数量大于0时,hasRecentTasks为true
opts = hasRecentTasks
? getHomeTransitionActivityOptions() // 是这个,一直过渡动画
: getUnknownTransitionActivityOptions();
}
// 见1.2.3
startRecentsActivity(opts);
mLastToggleTime = SystemClock.elapsedRealtime();
}
主要做启动RecentsActivity之前的一些准备工作
文件:RecentsImpl.java
private void startRecentsActivity(ActivityOptions opts) {
Intent intent = new Intent();
intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
if (opts != null) {
// 启动 RecentsActivity
mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
} else {
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
EventBus.getDefault().send(new RecentsActivityStartingEvent());
}
我们先来看看onCreate
文件:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFinishedOnStartup = false;
// 如果在Recents组件初始化完毕之前就启动了该Activity,那么就finish该Acitivity
// 这种情况一般发生在debug时,push SysUI apk的时候
SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp == null) {
mFinishedOnStartup = true;
finish();
return;
}
// Register this activity with the event bus
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
// 初始化包监听器
// 包监听器用来监听从PackageManagerd到recent list里面内容的更新
mPackageMonitor = new RecentsPackageMonitor();
mPackageMonitor.register(this);
// Set the Recents layout
setContentView(R.layout.recents);
takeKeyEvents(true); // 即使在Activity中没有取得焦点的View,也会处理此按键事件
mRecentsView = (RecentsView) findViewById(R.id.recents_view);
mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mScrimViews = new SystemBarScrimViews(this);
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
Configuration appConfiguration = Utilities.getAppConfiguration(this);
mLastDeviceOrientation = appConfiguration.orientation;
mLastDisplayDensity = appConfiguration.densityDpi;
mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
@Override
public void run() {
dismissRecentsToFocusedTask(MetricsEvent.OVERVIEW_SELECT_TIMEOUT);
}
});
// Set the window background
getWindow().setBackgroundDrawable(mRecentsView.getBackgroundScrim());
// Create the home intent runnable
mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
mHomeIntent.addCategory(Intent.CATEGORY_HOME);
mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
// 注册广播监听器,坚挺灭屏和时间变化的广播
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_TIME_CHANGED);
registerReceiver(mSystemBroadcastReceiver, filter);
getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION);
// 见1.3.1 重新加载stack view
reloadStackView();
}
文件:RecentsActivity.java
private void reloadStackView() {
// If the Recents component has preloaded a load plan, then use that to prevent
// reconstructing the task stack
RecentsTaskLoader loader = Recents.getTaskLoader();
RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan();
if (loadPlan == null) {
loadPlan = loader.createLoadPlan(this);
}
// Start loading tasks according to the load plan
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
if (!loadPlan.hasTasks()) {
// 见2, 加载任务
loader.preloadTasks(loadPlan, launchState.launchedToTaskId,
!launchState.launchedFromHome);
}
RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
loadOpts.runningTaskId = launchState.launchedToTaskId;
loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
loader.loadTasks(this, loadPlan, loadOpts);
TaskStack stack = loadPlan.getTaskStack();
mRecentsView.onReload(mIsVisible, stack.getTaskCount() == 0);
mRecentsView.updateStack(stack, true /* setStackViewTasks */);
// Update the nav bar scrim, but defer the animation until the enter-window event
boolean animateNavBarScrim = !launchState.launchedViaDockGesture;
mScrimViews.updateNavBarScrim(animateNavBarScrim, stack.getTaskCount() > 0, null);
// If this is a new instance relaunched by AM, without going through the normal mechanisms,
// then we have to manually trigger the enter animation state
boolean wasLaunchedByAm = !launchState.launchedFromHome &&
!launchState.launchedFromApp;
if (wasLaunchedByAm) {
EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
}
// Keep track of whether we launched from the nav bar button or via alt-tab
if (launchState.launchedWithAltTab) {
MetricsLogger.count(this, "overview_trigger_alttab", 1);
} else {
MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
}
// Keep track of whether we launched from an app or from home
if (launchState.launchedFromApp) {
Task launchTarget = stack.getLaunchTarget();
int launchTaskIndexInStack = launchTarget != null
? stack.indexOfStackTask(launchTarget)
: 0;
MetricsLogger.count(this, "overview_source_app", 1);
// If from an app, track the stack index of the app in the stack (for affiliated tasks)
MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
} else {
MetricsLogger.count(this, "overview_source_home", 1);
}
// Keep track of the total stack task count
int taskCount = mRecentsView.getStack().getTaskCount();
MetricsLogger.histogram(this, "overview_task_count", taskCount);
// After we have resumed, set the visible state until the next onStop() call
mIsVisible = true;
}
如果loadPlan.hasTasks()等于false,那么通过preLoadTasks来加载Task,接下来我们进入第二部份—Task的获取