1.Recent Panel按键处理流程
SystemUI有一个很重要的功能就是显示近期使用的app,方便用户点击使用。
手机长按HOME键或者点击Navigation Bar的近期任务栏虚拟键可以显示Recent Panel。
我这里手头上只有Android TV平台,并且也便于debug,所以讲讲收到Switch按键后,Recent Panel的显示流程。
KeyEvent.java中对于Switch按键的定义:
/** Key code constant: App switch key.
* Should bring up the application switcher dialog. */
public static final int KEYCODE_APP_SWITCH = 187;
* Should bring up the application switcher dialog. */
public static final int KEYCODE_APP_SWITCH = 187;
从KeyCode的定义可以看到Recent Panel的作用是the application switcher dialog。
当KeyEvent给到WindowManagerService之前,会先给到PhoneWindowManager处理(给系统一次机会,去处理按键消息)。
在KeyEvent出队列时,会走到interceptKeyBeforeDispatching函数,因此对于KEYCODE_APP_SWITCH的处理,会在这里进行。
/** {@inheritDoc} */
@Override
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
@Override
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
....
else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
if (!keyguardOn) {
if (down && repeatCount == 0) {
preloadRecentApps();
} else if (!down) {
toggleRecentApps();
}
}
return -1;
}
if (!keyguardOn) {
if (down && repeatCount == 0) {
preloadRecentApps();
} else if (!down) {
toggleRecentApps();
}
}
return -1;
}
在key down时,load最近使用的apps->preloadRecentApps();
在key up时,打开或关闭Recent Panel-> toggleRecentApps();
2.Recent Apps加载流程
在PhoneWindowManager里面开始执行preloadRecentApps()函数后,一步步调用,最终会call到我们熟悉的Recents.java,即最终是通过SystemUI去Reload Recent apps。
下面是这个函数的逻辑时序图:
预加载Recent Apps核心函数是Recents.java中的preloadRecentsInternal函数。
函数代码如下:
void preloadRecentsInternal() {
// Preload only the raw task list into a new load plan (which will be consumed by the
// RecentsActivity) only if there is a task to animate to.
ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
MutableBoolean topTaskHome = new MutableBoolean(true);
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
sInstanceLoadPlan = loader.createLoadPlan(mContext);
if (topTask != null && !mSystemServicesProxy.isRecentsTopMost(topTask, topTaskHome)) {
sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
TaskStack top = sInstanceLoadPlan.getAllTaskStacks().get(0);
if (top.getTaskCount() > 0) {
preCacheThumbnailTransitionBitmapAsync(topTask, top, mDummyStackView,
topTaskHome.value);
}
}
}
函数主要做了如下几件事情:
1)获取当前运行的Task
ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
/** Returns the top task. */
public ActivityManager.RunningTaskInfo getTopMostTask() {
List<ActivityManager.RunningTaskInfo> tasks = getRunningTasks(1);
if (tasks != null && !tasks.isEmpty()) {
return tasks.get(0);
}
return null;
}
public ActivityManager.RunningTaskInfo getTopMostTask() {
List<ActivityManager.RunningTaskInfo> tasks = getRunningTasks(1);
if (tasks != null && !tasks.isEmpty()) {
return tasks.get(0);
}
return null;
}
/** Returns a list of the running tasks */
private List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
if (mAm == null) return null;
return mAm.getRunningTasks
private List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
if (mAm == null) return null;
return mAm.getRunningTasks