Android8.1 SystemUI中Recents(多任務(wù)),"全部清除"按鈕點(diǎn)擊事件簡(jiǎn)單梳理

版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/qq_30552095/article/details/87932081
最近有一個(gè)需求,
現(xiàn)象:播放音樂(lè)時(shí),點(diǎn)擊多任務(wù)中的“全部清除”按鈕,音樂(lè)未停止;
預(yù)期:音樂(lè)停止。

于是去看看這個(gè)按鈕的點(diǎn)擊事件,本來(lái)以為這就是一個(gè)簡(jiǎn)單的onclick事件,可是并沒(méi)有這么簡(jiǎn)單,首先找到這個(gè)按鈕:
com.android.systemui.recents.views.RecentsView中的mStackActionButton,這個(gè)就是按鈕的對(duì)象了,可是這個(gè)按鈕并沒(méi)有找到onclick事件,所以猜測(cè)是不是在onTouchEvent中處理的
com.android.systemui.recents.views.RecentsView -> onTouchEvent()

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

繼續(xù)跟,RecentsViewTouchHandler這個(gè)類很像是專門處理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;
                }
  ......
            }

這里就是處理點(diǎn)擊事件的地方了,繼續(xù)跟到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<EventHandler> 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<EventHandler>) 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();
        }
    }

通過(guò)打斷點(diǎn)發(fā)現(xiàn)走的是 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());
        }
    }

這里調(diào)用的反射,仍然是通過(guò)斷點(diǎn),發(fā)現(xiàn)走的是eventHandler.method.invoke(sub, event);
sub是com.android.systemui.recents.views.TaskStackView
event是com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent
在TaskStackView中找到這個(gè)方法
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<Task> 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);
            }
        });

    }

找到關(guān)鍵的一句代碼EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
這里又走到了EventBus中,同樣的在
com.android.systemui.recents.events.EventBus -> processEvent();
這個(gè)方法中的eventHandler.method.invoke(sub, event);
sub是com.android.systemui.recents.RecentsActivity
event是com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
找到這個(gè)方法
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);
        });
    }

這個(gè)就比較明確了,就是調(diào)用了ActivityManager中的removeTask方法。
由此可見(jiàn),recents中的task都是放在了ActivityManger中的。

--------------------------------------------------------------------分割線-------------------------------------------------------------------

回到我的需求,需要在移除task的時(shí)候,將音樂(lè)停止,那就在這個(gè)地方將這個(gè)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();中調(diào)用新增的方法

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);
    }

————————————————
版權(quán)聲明:本文為CSDN博主「Shawn」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_30552095/article/details/87932081

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容