在安卓系统中,我们经常使用清除最近应用列表,或者是”一键清除“这个功能,最近在系统开发中,需要在一键清除时,保留某个应用不被杀死,需要做一些修改,所以就需要最一键清除这个流程进行了解。
长按HOME键会打开最近的APP列表,打开最近APP列表会执行下面的代码:

  1. IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
  2. ServiceManager.getService("statusbar"));
  3. try {
  4. statusBarService.toggleRecentApps();
  5. } catch (RemoteException e) {
  6. Slog.e(LOG_TAG, "Error toggling recent apps.");
  7. }

IStatusBarService给了我们一个很明确的方向就是StatusBarService,在StatusBarManagerService类中,toggleRecentApps()的源码如下:

  1. @Override
  2. public void toggleRecentApps() {
  3. if (mBar != null) {
  4. try {
  5. mBar.toggleRecentApps();
  6. } catch (RemoteException ex) {}
  7. }
  8. }

mBar的赋值在:

  1. @Override
  2. public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
  3. List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
  4. Rect fullscreenStackBounds, Rect dockedStackBounds) {
  5. ......
  6. mBar = bar;
  7. ......

在BaseStatusBar类的start方法中调用了StatusBarManagerService.registerStatusBar方法,下面是调用这个方法的语句:

  1. mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);

mCommandQueue被赋值给了StatusBarManagerService.mBar,下面是对这个变量赋值的语句:

  1. mCommandQueue = new CommandQueue(this, iconList);

这是CommandQueue类的对象,这个类的代码在文件”frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java”中。
回到StatusBarManagerService.toggleRecentApps方法中,在这个方法中执行了mBar.toggleRecentApps();语句,在这里调用的toggleRecentApps方法是CommandQueue.toggleRecentApps方法,下面来看一下CommandQueue.toggleRecentApps方法的的源码:

  1. public void toggleRecentApps() {
  2. synchronized (mList) {
  3. ......
  4. mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget();
  5. }
  6. }

追溯MSG_TOGGLE_RECENT_APPS,从CommandQueue.mHandler到BaseStatusBar.toggleRecentApps到BaseStatusBar.H.handleMessage依次调用,代码如下

  1. //CommandQueue.H.handleMessage:
  2. public void handleMessage(Message msg) {
  3. if (mPaused) {
  4. this.sendMessageAtFrontOfQueue(Message.obtain(msg));
  5. return;
  6. }
  7. final int what = msg.what & MSG_MASK;
  8. switch (what) {
  9. ......
  10. case MSG_TOGGLE_RECENT_APPS:
  11. mCallbacks.toggleRecentApps();
  12. break;
  13. ......
  14. }
  15. }
  1. //BaseStatusBar.toggleRecentApps:
  2. @Override
  3. public void toggleRecentApps() {
  4. int msg = MSG_TOGGLE_RECENTS_APPS;
  5. ......
  6. mHandler.sendEmptyMessage(msg);
  7. }
  1. BaseStatusBar.H.handleMessage
  2. public void handleMessage(Message m) {
  3. switch (m.what) {
  4. ......
  5. case MSG_TOGGLE_RECENTS_APPS:
  6. if (mDeviceProvisioned) {
  7. toggleRecents();
  8. }
  9. break;
  10. ......
  11. }
  12. }

这里简单介绍一下statusbar的细节,BaseStatusBar有三个子类:PhoneStatusBar, CarStatusBar, TvStatusBar,很明显我们需要关注的的是PhoneStatusBar
面是PhoneStatusBar.toggleRecents方法的源码:

  1. @Override
  2. protected void toggleRecents() {
  3. // Toggle the recents visibility flag
  4. mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE;
  5. notifyUiVisibilityChanged(mSystemUiVisibility);
  6. super.toggleRecents();
  7. }

前两行语句设置了一下状态,然后就调用父类的toggleRecents方法,PhoneStatusBar的父类是BaseStatusBar。
下面是BaseStatusBar.toggleRecents方法的源码:

  1. protected void toggleRecents() {
  2. if (mRecents != null) {
  3. sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
  4. mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
  5. }
  6. }

mRecents实际调用的是Recents类的对象。Recents类代码在文件”frameworks/base/packages/SystemUI/src/com/android/systemui/recent/Recents.java”中。 下面是Recents.toggleRecents方法的代码:

  1. @Override
  2. public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
  3. ......
  4. try {
  5. Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
  6. intent.setClassName("com.android.systemui",
  7. "com.android.systemui.recent.RecentsActivity");
  8. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
  9. | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
  10. ......
  11. startActivitySafely(intent, opts.toBundle());
  12. }
  13. } catch (ActivityNotFoundException e) {
  14. Log.e(TAG, "Failed to launch RecentAppsIntent", e);
  15. }
  16. }

Recents.toggleRecents方法启动了RecentsActivity。RecentsActivity类的代码在文件”frameworks/base/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java”中,RecentsActivity的layout是R.layout.recents 查看xml,其中核心的只有com.android.systemui.recents.views.RecentsView这个控件,这个RecentsView位于”frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/“ 在RecentView中那个“一键清理”的按钮是

  1. mStackActionButton = (TextView) inflater.inflate(Recents.getConfiguration().isLowRamDevice
  2. ? R.layout.recents_low_ram_stack_action_button
  3. : R.layout.recents_stack_action_button,
  4. this, false);

mStackActionButton的点击功能位于android/systemui/recents/views/RecentsViewTouchHandler.java中,在RecentsView的点击事件通过RecentsViewTouchHandler进行处理。RecentsViewTouchHandler中处理点击事件的代码如下:

  1. private boolean handleTouchEvent(MotionEvent ev) {
  2. int action = ev.getActionMasked();
  3. ......
  4. case MotionEvent.ACTION_UP:
  5. case MotionEvent.ACTION_CANCEL: {
  6. if (mRv.getStackActionButton().isPressed() && isWithinStackActionButton(evX, evY)) {
  7. EventBus.getDefault().send(new DismissAllTaskViewsEvent());
  8. consumed = true;
  9. }
  10. }
  11. .......
  12. return consumed;
  13. }
  14. 追溯DismissAllTaskViewsEvent,可以找到两个地方,一个回到RecentView
  15. ``` java
  16. public final void onBusEvent(DismissAllTaskViewsEvent event) {
  17. SystemServicesProxy ssp = Recents.getSystemServices();
  18. if (!ssp.hasDockedTask()) {
  19. // Animate the background away only if we are dismissing Recents to home
  20. animateBackgroundScrim(0f, DEFAULT_UPDATE_SCRIM_DURATION);
  21. }

BackgroundScrim是在最近应用视图中,在下方的一个渐变的颜色,这里让它动态消失,另一个是frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java中的

  1. public final void onBusEvent(final DismissAllTaskViewsEvent event) {
  2. // Keep track of the tasks which will have their data removed
  3. ArrayList<Task> tasks = new ArrayList<>(mStack.getTasks());
  4. mAnimationHelper.startDeleteAllTasksAnimation(
  5. getTaskViews(), useGridLayout(), event.getAnimationTrigger());
  6. event.addPostAnimationCallback(new Runnable() {
  7. @Override
  8. public void run() {
  9. // Remove all tasks and delete the task data for all tasks
  10. mStack.removeAllTasks(true /* notifyStackChanges */);
  11. for (int i = tasks.size() - 1; i >= 0; i--) {
  12. EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
  13. }
  14. }
  15. });
  16. }

首先执行

  1. mAnimationHelper.startDeleteAllTasksAnimation(
  2. getTaskViews(), useGridLayout(), event.getAnimationTrigger());

这里就是展示动画,把界面上显示的任务显示一个动画后清屏 ,在callback中的重点是mStack.removeAllTasks(true /* notifyStackChanges */);EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));mStack.removeAllTasks(true /* notifyStackChanges */);调用了frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java的removeAllTasks

  1. public void removeAllTasks(boolean notifyStackChanges) {
  2. ArrayList<Task> tasks = mStackTaskList.getTasks();
  3. for (int i = tasks.size() - 1; i >= 0; i--) {
  4. Task t = tasks.get(i);
  5. mStackTaskList.remove(t);
  6. mRawTaskList.remove(t);
  7. }
  8. if (mCb != null && notifyStackChanges) {
  9. // Notify that all tasks have been removed
  10. mCb.onStackTasksRemoved(this);
  11. }
  12. }

mCb是TaskStackCallbacks,TaskStackView实现了这一接口

  1. @Override
  2. public void onStackTasksRemoved(TaskStack stack) {
  3. // Reset the focused task
  4. resetFocusedTask(getFocusedTask());
  5. // Return all the views to the pool
  6. List<TaskView> taskViews = new ArrayList<>();
  7. taskViews.addAll(getTaskViews());
  8. for (int i = taskViews.size() - 1; i >= 0; i--) {
  9. mViewPool.returnViewToPool(taskViews.get(i));
  10. }
  11. // Remove all the ignore tasks
  12. mIgnoreTasks.clear();
  13. // If there are no remaining tasks, then just close recents
  14. EventBus.getDefault().send(new AllTaskViewsDismissedEvent(
  15. R.string.recents_empty_message_dismissed_all));
  16. }

回到EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));追溯执行位置在RecentActivity中,代码如下

  1. public final void onBusEvent(DeleteTaskDataEvent event) {
  2. // Remove any stored data from the loader
  3. RecentsTaskLoader loader = Recents.getTaskLoader();
  4. loader.deleteTaskData(event.task, false);
  5. // Remove the task from activity manager
  6. ActivityManagerWrapper.getInstance().removeTask(event.task.key.id);
  7. }

最终调用了ActivityManagerWrapper.getInstance().removeTask(event.task.key.id);,ActivityManagerWrapper的removeTask代码如下

  1. public void removeTask(int taskId) {
  2. mBackgroundExecutor.submit(new Runnable() {
  3. @Override
  4. public void run() {
  5. try {
  6. ActivityManager.getService().removeTask(taskId);
  7. } catch (RemoteException e) {
  8. Log.w(TAG, "Failed to remove task=" + taskId, e);
  9. }
  10. }
  11. });
  12. }

最终是调用了ActivityManager.getService().removeTask(taskId);结束了这一task。

总结

结束最近使用APP的过程,是从statusbar,到recentActivity,显示最近应用的列表,在界面中显示RecentView,RecentView包括应用列表和清除所有应用的文字,点击一键清除调用到了RecentsViewTouchHandler,之后通过eventbus和handler调用到了TaskStackView,之后就区分两部分,一部分执行动画,一部分处理taskstack的数据,最终会调用到AMS的removeTask结束task。