Android8.1 SystemUI中Recents(多任务),"全部清除"按钮点击事件简单梳理

最近有一个需求,
现象:播放音乐时,点击多任务中的“全部清除”按钮,音乐未停止;
预期:音乐停止。

于是去看看这个按钮的点击事件,本来以为这就是一个简单的onclick事件,可是并没有这么简单,首先找到这个按钮:
com.android.systemui.recents.views.RecentsView中的mStackActionButton,这个就是按钮的对象了,可是这个按钮并没有找到onclick事件,所以猜测是不是在onTouchEvent中处理的
com.android.systemui.recents.views.RecentsView -> onTouchEvent()

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        return mTouchHandler.onTouchEvent(ev);
    }

继续跟,RecentsViewTouchHandler这个类很像是专门处理recentsView的touch事件的
com.android.systemui.recents.views.RecentsViewTouchHandler ->onTouchEvent();

public boolean onTouchEvent(MotionEvent ev) {
        handleTouchEvent(ev);
        if (ev.getAction() == MotionEvent.ACTION_UP && mRv.getStack().getStackTaskCount() == 0) {
            EventBus.getDefault().send(new HideRecentsEvent(false, true));
        }
        return true;
    }

在com.android.systemui.recents.views.RecentsViewTouchHandler -> handleTouchEvent(ev)
中的ACTION_UP事件中找到了

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                if (mRv.getStackActionButton().isPressed() && isWithinStackActionButton(evX, evY)) {
                    EventBus.getDefault().send(new DismissAllTaskViewsEvent());
                    consumed = true;
                }
  ......
            }

这里就是处理点击事件的地方了,继续跟到EventBus中
com.android.systemui.recents.events.EventBus -> send();

public void send(Event event) {
       ......
        queueEvent(event);
    }

com.android.systemui.recents.events.EventBus -> queueEvent();

 private void queueEvent(final Event event) {
        ArrayList eventHandlers = mEventTypeMap.get(event.getClass());
        if (eventHandlers == null) {
            // This is just an optimization to return early if there are no handlers. However, we
            // should still ensure that we call pre/post dispatch callbacks so that AnimatedEvents
            // are still cleaned up correctly if a listener has not been registered to handle them
            event.onPreDispatch();
            event.onPostDispatch();
            return;
        }

        // Prepare this event
        boolean hasPostedEvent = false;
        event.onPreDispatch();

        // We need to clone the list in case a subscriber unregisters itself during traversal
        // TODO: Investigate whether we can skip the object creation here
        eventHandlers = (ArrayList) eventHandlers.clone();
        int eventHandlerCount = eventHandlers.size();
        for (int i = 0; i < eventHandlerCount; i++) {
            final EventHandler eventHandler = eventHandlers.get(i);
            if (eventHandler.subscriber.getReference() != null) {
                if (event.requiresPost) {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            processEvent(eventHandler, event);
                        }
                    });
                    hasPostedEvent = true;
                } else {
                    processEvent(eventHandler, event);
                }
            }
        }

        // Clean up after this event, deferring until all subscribers have been called
        if (hasPostedEvent) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    event.onPostDispatch();
                }
            });
        } else {
            event.onPostDispatch();
        }
    }

通过打断点发现走的是 processEvent(eventHandler, event);
com.android.systemui.recents.events.EventBus -> processEvent();

private void processEvent(final EventHandler eventHandler, final Event event) {
        // Skip if the event was already cancelled
        if (event.cancelled) {
            if (event.trace || DEBUG_TRACE_ALL) {
                logWithPid("Event dispatch cancelled");
            }
            return;
        }

        try {
            if (event.trace || DEBUG_TRACE_ALL) {
                logWithPid(" -> " + eventHandler.toString());
            }
            Object sub = eventHandler.subscriber.getReference();
            if (sub != null) {
                long t1 = 0;
                if (DEBUG_TRACE_ALL) {
                    t1 = SystemClock.currentTimeMicro();
                }
                eventHandler.method.invoke(sub, event);
                if (DEBUG_TRACE_ALL) {
                    long duration = (SystemClock.currentTimeMicro() - t1);
                    mCallDurationMicros += duration;
                    mCallCount++;
                    logWithPid(eventHandler.method.toString() + " duration: " + duration +
                            " microseconds, avg: " + (mCallDurationMicros / mCallCount));
                }
            } else {
                Log.e(TAG, "Failed to deliver event to null subscriber");
            }
        } catch (IllegalAccessException e) {
            Log.e(TAG, "Failed to invoke method", e.getCause());
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e.getCause());
        }
    }

这里调用的反射,仍然是通过断点,发现走的是eventHandler.method.invoke(sub, event);
sub是com.android.systemui.recents.views.TaskStackView
event是com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent
在TaskStackView中找到这个方法
com.android.systemui.recents.views.TaskStackView -> onBusEvent();

public final void onBusEvent(final DismissAllTaskViewsEvent event) {
        // Keep track of the tasks which will have their data removed
        ArrayList tasks = new ArrayList<>(mStack.getStackTasks());
        mAnimationHelper.startDeleteAllTasksAnimation(
                getTaskViews(), useGridLayout(), event.getAnimationTrigger());
        event.addPostAnimationCallback(new Runnable() {
            @Override
            public void run() {
                // Announce for accessibility
                announceForAccessibility(getContext().getString(
                        R.string.accessibility_recents_all_items_dismissed));

                // Remove all tasks and delete the task data for all tasks
                mStack.removeAllTasks(true /* notifyStackChanges */);
                for (int i = tasks.size() - 1; i >= 0; i--) {
                    EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
                }

                MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS_ALL);
            }
        });

    }

找到关键的一句代码EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
这里又走到了EventBus中,同样的在
com.android.systemui.recents.events.EventBus -> processEvent();
这个方法中的eventHandler.method.invoke(sub, event);
sub是com.android.systemui.recents.RecentsActivity
event是com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
找到这个方法
com.android.systemui.recents.RecentsActivity -> onBusEvent();

public final void onBusEvent(DeleteTaskDataEvent event) {
        // Remove any stored data from the loader
        RecentsTaskLoader loader = Recents.getTaskLoader();
        loader.deleteTaskData(event.task, false);

        // Remove the task from activity manager
        SystemServicesProxy ssp = Recents.getSystemServices();
        ssp.removeTask(event.task.key.id);
    }

跟到SystemServicesProxy中看看
com.android.systemui.recents.misc.SystemServicesProxy -> removeTask();

public void removeTask(final int taskId) {
        if (mAm == null) return;
        if (RecentsDebugFlags.Static.EnableMockTasks) return;

        // Remove the task.
        mUiOffloadThread.submit(() -> {
            mAm.removeTask(taskId);
        });
    }

这个就比较明确了,就是调用了ActivityManager中的removeTask方法。
由此可见,recents中的task都是放在了ActivityManger中的。

--------------------------------------------------------------------分割线-------------------------------------------------------------------

回到我的需求,需要在移除task的时候,将音乐停止,那就在这个地方将这个package停止
增加方法
com.android.systemui.recents.misc.SystemServicesProxy

public void removeTask(final Task.TaskKey key) {
        removeTask(key.id);
        if (mAm == null || key.getComponent() == null || TextUtils.isEmpty(key.getComponent().getPackageName())) {
            return;
        }
        mAm.forceStopPackage(key.getComponent().getPackageName());
    }

在com.android.systemui.recents.RecentsActivity -> onBusEvent();中调用新增的方法

public final void onBusEvent(DeleteTaskDataEvent event) {
        // Remove any stored data from the loader
        RecentsTaskLoader loader = Recents.getTaskLoader();
        loader.deleteTaskData(event.task, false);

        // Remove the task from activity manager
        SystemServicesProxy ssp = Recents.getSystemServices();
//      ssp.removeTask(event.task.key.id);
        ssp.removeTask(event.task.key);
    }

你可能感兴趣的:(Android)