最近有一个需求,
现象:播放音乐时,点击多任务中的“全部清除”按钮,音乐未停止;
预期:音乐停止。
于是去看看这个按钮的点击事件,本来以为这就是一个简单的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);
}