Android11 最近任务Recents功能分析,分析的很彻底
Posted 憨潇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android11 最近任务Recents功能分析,分析的很彻底相关的知识,希望对你有一定的参考价值。
android11 最近任务Recents功能分析
一、初始化
1、Recents.java
Recents继承SystemUI,进程启动后会在Dependency里面通过@Inject进行初始化,然后在SystemUIService里面调用SystemUIApplication的startServicesIfNeeded()里面进行启动:
private final RecentsImplementation mImpl
@Overridepublic void start()
//加入callback
mCommandQueue.addCallback(this);
mImpl.onStart(mContext);
RecentsImplementation替代了之前的RecentsImpl,是一个interface,由其实现类OverviewProxyRecentsImpl来执行操作
2、OverviewProxyRecentsImpl.java
private OverviewProxyService mOverviewProxyService;@Overridepublic void onStart(Context context)
;;;;;;;;;;;;;;;;;;;;;;
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
这个是根据调用关系,在onStart里面创建了OverviewProxyService对象。
3、OverviewProxyService.java
中间类,在该类内部去绑定远端的Service
@Injectpublic OverviewProxyService(Context context, CommandQueue commandQueue,
NavigationBarController navBarController, NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
PipUI pipUI, Optional<Divider> dividerOptional,
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
BroadcastDispatcher broadcastDispatcher)
super(broadcastDispatcher);
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
.setPackage(mRecentsComponentName.getPackageName());
;;;;;;;;;;;;;;;;;;;;;;;;;;;
// Connect to the service
updateEnabledState();
startConnectionToCurrentUser();
在接着去查看startConnectionToCurrentUser方法。
public void startConnectionToCurrentUser()
if (mHandler.getLooper() != Looper.myLooper())
mHandler.post(mConnectionRunnable);
else
internalConnectToCurrentUser();
一步步往下走
private void internalConnectToCurrentUser()
;;;;;;;;;;;;;;;;;;;;;;;;;;
Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
.setPackage(mRecentsComponentName.getPackageName());
try
mBound = mContext.bindServiceAsUser(launcherServiceIntent,
mOverviewServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
UserHandle.of(getCurrentUserId()));
;;;;;;;;;;;;;;;;;;;;;;;;;
又调用了
private IOverviewProxy mOverviewProxy;private final ServiceConnection mOverviewServiceConnection = new ServiceConnection()
@Override
public void onServiceConnected(ComponentName name, IBinder service)
;;;;;;;;;;;;;;;;;;;;
mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
;;;;;;;;;;;;;;;;;;;;;;;;
跟随调用关系来看,在构造方法内部,会去执行startConnectionToCurrentUser来调用bindServiceAsUser()去启动service,在onServiceConnected中,通过IOverviewProxy.Stub.asInterface(service)来获取IOverviewProxy实例,后续会用到;Service对应的Intent为android.intent.action.QUICKSTEP_SERVICE,R.string.config_recentsComponentName对应如下,用来获取远端服务的应用包名。
<string name="config_recentsComponentName" translatable="false"
>com.android.launcher3/com.android.quickstep.RecentsActivity</string>
从ComponentName可以看到,被bind的service是在Launcher3里面,接下来一起看一下对应的远端Service;
4、TouchInteractionService.java
Launcher3内的入口类,通过该类来调用相关逻辑
private final IBinder mMyBinder = new IOverviewProxy.Stub()
;;;;;;;;;;;;;;;;;;;;;;;;;;
@BinderThread
@Override
public void onOverviewToggle()
mOverviewCommandHelper.onOverviewToggle();
;;;;;;;;;;;;;;;;;;;
@Overridepublic IBinder onBind(Intent intent)
return mMyBinder;
可以看到,TouchInteractionService里面创建了IOverviewProxy.Stub实例,然后在onBind()返回;
TouchInteractionService是一个Service,在onCreate()里面进行了一些初始化相关的调用
@Overridepublic void onCreate()
super.onCreate();
;;;;;;;;;;;;;;;;;;;;
mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
;;;;;;;;;;;;;;;;;;;;
sConnected = true;
@UiThreadpublic void onUserUnlocked()
;;;;;;;;;;;;;
mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState,
mOverviewComponentObserver);
;;;;;;;;;;;;;;;;;;;;;;;;
可以看到,在TouchInteractionService启动后,会创建OverviewComponentObserver实例和OverviewCommandHelper实例,一起看一下这两个类的实现
5、OverviewComponentObserver.java
public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class);
mFallbackIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_DEFAULT)
.setComponent(fallbackComponent)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
;;;;;;;;;;;;;;;;;;;;;;
updateOverviewTargets();
在这个里面可以看见,在构造方法内部会创建mFallbackIntent,从组成来看,通过该Intent启动RecentsActivity,最后来去看 updateOverviewTargets这个方法
private void updateOverviewTargets()
;;;;;;;;;;;;;;;;;;
mActivityInterface = FallbackActivityInterface.INSTANCE;
mIsHomeAndOverviewSame = false;
mOverviewIntent = mFallbackIntent;
;;;;;;;;;;;;;;;;;
在这个方法的内部,会将mFallbackIntent赋值给mOverviewIntent,后续启动Recents就会用到mOverviewIntent。
6、OverviewCommandHelper.java
启动Recents的直接入口类,最终会去实现onOverviewToggle
public OverviewCommandHelper(Context context, RecentsAnimationDeviceState deviceState,
OverviewComponentObserver observer)
;;;;;;;;;;;;;;;;;;;;;
mRecentsModel = RecentsModel.INSTANCE.get(mContext);
mOverviewComponentObserver = observer;
@BinderThreadpublic void onOverviewToggle()
;;;;;;;;;;;;;;;;;;;;
ActivityManagerWrapper.getInstance()
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
二、启动
入口都是在PhoneWindowManager,直接从接收来分析接收类toggleRecentApps
1、Recents.java
@Overridepublic void toggleRecentApps()
;;;;;;;;;;;;;;;;;;;
mImpl.toggleRecentApps();
这里启动了这个类,去进行查看
2、OverviewProxyRecentsImpl.java
@Overridepublic void toggleRecentApps()
// If connected to launcher service, let it handle the toggle logic
IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
if (overviewProxy != null)
final Runnable toggleRecents = () ->
try
if (mOverviewProxyService.getProxy() != null)
mOverviewProxyService.getProxy().onOverviewToggle();
mOverviewProxyService.notifyToggleRecentApps();
catch (RemoteException e)
Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
;
//启动runnable
这里就是在runnable内部会通过OverviewProxyService的getProxy()来获取到Launcher3实现的IOveriewProxy对象引用,然后调用onOverviewToggle()方法。
3、TouchInteractionService.java
@BinderThread@Overridepublic void onOverviewToggle()
mOverviewCommandHelper.onOverviewToggle();
继续往下走,可以看见启动OverviewCommandHelper中的onOverviewToggle
4、OverviewCommandHelper.java
@BinderThread
public void onOverviewToggle()
ActivityManagerWrapper.getInstance()
.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
这里可以看见在执行onOverviewToggle()后,实际上是通过Executoe执行了RecentsActivityCommand。
private class RecentsActivityCommand<T extends StatefulActivity<?>> implements Runnable
;;;;;;;;;;;;;;;;;;;;;;;
public RecentsActivityCommand()
mActivityInterface = mOverviewComponentObserver.getActivityInterface();
;;;;;;;;;;;;;;
//预加载,Android8.1也有相同的逻辑
mRecentsModel.getTasks(null);
@Override
public void run()
;;;;;;;;;;;;;;;;;;;;;;;;;
// Otherwise, start overview.
mListener = mActivityInterface.createActivityInitListener(this::onActivityReady);
mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(),
new RemoteAnimationProvider()
@Override
public AnimatorSet createWindowAnimation(
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets)
return RecentsActivityCommand.this.createWindowAnimation(appTargets,
wallpaperTargets);
, mContext, MAIN_EXECUTOR.getHandler(),
mAnimationProvider.getRecentsLaunchDuration());
可以看到,最终是通过registerAndStartActivity()来启动了intent,前面分析到mOverviewComponentObserver.getOverviewIntent()对应的就是mFallbackIntent,最终启动了RecentsActivity;
三、显示
在启动RecentsActivity后,会显示最近任务列表,看一下具体工作流程
1、RecentsActivity.java
Recents显示Activity
@Overrideprotected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
;;;;;;;;;;;;;;;;;;;;;;;;;;
setupViews();
;;;;;;;;;;;;;;;;;;;;;;;;
protected void setupViews()
inflateRootView(R.layout.fallback_recents_activity);
setContentView(getRootView());
mDragLayer = findViewById(R.id.drag_layer);
mFallbackRecentsView = findViewById(R.id.overview_panel);
mActionsView = findViewById(R.id.overview_actions_view);
mDragLayer.recreateControllers();
mFallbackRecentsView.init(mActionsView);
RecentsActivity继承了StatefulActivity,有些方法实现是在父类里面执行的,在onCreate()里面执行setupViews(),初始化了FallbackRecentsView,FallbackRecentsView继承了RecentsView,主要逻辑都是在RecentsView里面实现的,直接看RecentsView的实现逻辑:
2、RecentsView.java
Recents显示主View
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
BaseActivityInterface sizeStrategy)
super(context, attrs, defStyleAttr);
;;;;;;;;;;;;;;;;;;;;;;;
mModel = RecentsModel.INSTANCE.get(context);
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
.inflate(R.layout.overview_clear_all_button, this, false);
mClearAllButton.setOnClickListener(this::dismissAllTasks);
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
10 /* initial size */);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
可以看见,在构造方法内部,获取了RecentsModel实例,创建了ViewPool实例mTaskViewPool,该mTaskViewPool存储TaskView,对应的layout为 R.layout.task,最大数量为20;
@Overrideprotected void onAttachedToWindow()
super.onAttachedToWindow();
updateTaskStackListenerState();
;;;;;;;;;;;;;;;;;;;;;;;;;;;
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
//当snapshot更新时,会进行回调刷新UI
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
;;;;;;;;;;;;;;;;;;;;;;
在RecentsView显示时会回调onAttachedToWindow(),在内部执行了updateTaskStackListenerState(),然后做了一些注册回调操作,当有变化时,会进行回调通知来更新UI;
private void updateTaskStackListenerState()
boolean handleTaskStackChanges = mOverviewStateEnabled && isAttachedToWindow()
&& getWindowVisibility() == VISIBLE;
if (handleTaskStackChanges != mHandleTaskStackChanges)
mHandleTaskStackChanges = handleTaskStackChanges;
if (handleTaskStackChanges)
reloadIfNeeded();
在updateTaskStackListenerState()内部会进行一系列条件判断来确定是否执行reloadIfNeeded(),当首次进入时会执行reloadIfNeeded():
public void reloadIfNeeded()
if (!mModel.isTaskListValid(mTaskListChangeId))
mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
通过RecentsModel的getTasks()来获取任务列表,然后回到applyLoadPlan(),getTasks()逻辑在后面进行分析,先看一下applyLoadPlan()方法的执行逻辑:
protected void applyLoadPlan(ArrayList<Task> tasks)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
// Unload existing visible task data
unloadVisibleTaskData();
final int requiredTaskCount = tasks.size();
if (getTaskViewCount() != requiredTaskCount)
;;;;;;;;;;;;
for (int i = getTaskViewCount(); i < requiredTaskCount; i++)
addView(mTaskViewPool.getView());
;;;;;;;;;;;;;;;;;;;
if (requiredTaskCount > 0)
addView(mClearAllButton);
// Rebind and reset all task views
for (int i = requiredTaskCount - 1; i >= 0; i--)
final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
final Task task = tasks.get(i);
final TaskView taskView = (TaskView) getChildAt(pageIndex);
taskView.bind(task, mOrientationState);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
resetTaskVisuals();
;;;;;;;;;;;;;;;
在applyLoadPlan()内部,主要执行了四项工作:
1.unloadVisibleTaskData():将现有visible的task数据进行置空;
2.根据task数量(首次进入)进行addView,TaskView通过mTaskViewPool的getView()进行获取,最后添加clearAllButton;
3.对添加完的TaskView进行bind()操作,将对应的task存在TaskView内部,类似setTag()功能;
4.执行resetTaskVisuals()来刷新加载数据;
public void resetTaskVisuals()
;;;;;;;;;;;;;;;;;;;;;;;;;;
// Update the set of visible task's data
loadVisibleTaskData();
public void loadVisibleTaskData()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
// Update the task data for the in/visible children
for (int i = 0; i < getTaskViewCount(); i++)
TaskView taskView = getTaskViewAt(i);
Task task = taskView.getTask();
int index = indexOfChild(taskView);
boolean visible = lower <= index && index <= upper;
if (visible)
if (task == mTmpRunningTask)
// Skip loading if this is the task that we are animating into
continue;
if (!mHasVisibleTaskData.get(task.key.id))
taskView.onTaskListVisibilityChanged(true /* visible */);
mHasVisibleTaskData.put(task.key.id, visible);
最终在loadVisibleTaskData()里面通过TaskView的onTaskVisibilityChanged(true)来加载数据;
3、TaskView.java
Recents列表中Task对应的显示View
public void bind(Task task, RecentsOrientedState orientedState)
mTask = task;
mSnapshotView.bind(task);
继续往下看
public void onTaskListVisibilityChanged(boolean visible)
if (mTask == null)
return;
cancelPendingLoadTasks();
if (visible)
// These calls are no-ops if the data is already loaded, try and load the high
// resolution thumbnail if the state permits
RecentsModel model = RecentsModel.INSTANCE.get(getContext());
TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
TaskIconCache iconCache = model.getIconCache();
mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(
mTask, thumbnail -> mSnapshotView.setThumbnail(mTask, thumbnail));
mIconLoadRequest = iconCache.updateIconInBackground(mTask,
(task) ->
setIcon(task.icon);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask())
getRecentsView().updateLiveTileIcon(task.icon);
mDigitalWellBeingToast.initialize(mTask);
);
else
mSnapshotView.setThumbnail(null, null);
setIcon(null);
// Reset the task thumbnail reference as well (it will be fetched from the cache or
// reloaded next time we need it)
mTask.thumbnail = null;
在onTaskListVisibilityChanged()内部,当visible为true时,执行mSnapshotView.setThumbnail()和setIcon()分别来加载缩略图和icon;当visible为false时,将其置空;
public TaskView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
setOnClickListener((view) ->
if (getTask() == null)
return;
launchTask(true /* animate */);
;;;;;;;;;;;;;;;;;;;;;;;;;;
);
;;;;;;;;;;;;;;;;;;;;;;;;
public void launchTask(boolean animate)
launchTask(animate, false /* freezeTaskList */);
private void launchTaskInternal(boolean animate, boolean freezeTaskList,
Consumer<Boolean> resultCallback, Handler resultCallbackHandler)
if (mTask != null)
;;;;;;;;;;;;;;
ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
opts, resultCallback, resultCallbackHandler);
;;;;;;;;;;;;;;;;;;;;
getRecentsView().onTaskLaunched(mTask);
在TaskView内部设置了点击事件监听,当点击后会执行launchTask,最终会调用到ActivityManagerWrapper的startActivityFromRecentsAsync()来快速切换到对应的任务
4、RecentsModel.java
Recents数据获取功能管理类
private RecentsModel(Context context)
mContext = context;
mTaskList = new RecentTasksList(MAIN_EXECUTOR,
new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
mIconCache = new TaskIconCache(context, looper);
mThumbnailCache = new TaskThumbnailCache(context, looper);
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
1 RecentsModel继承了TaskStackChangeListener,在构造方法内部初始化了RecentsTaskList、TaskIconCache和TaskThumbnailCache实例,注册了registerTaskStackListener回调;分别来获取最近任务列表、获取Task对应的Icon和,
2 RecentsTaskList:获取最近任务列表;
3 TaskIconCache:获取Task对应的icon,并进行缓存;
4 TaskThumbnailCache:获取Task对应的thumbnailData,并进行缓存;
5 会通过TaskIconCache和TaskThumbnailCache进行分别存储管理,首次显示或有新的任务,需要通过TaskIconCache和TaskThumbnailCache执行对应的request去获取并进行cache存储
public int getTasks(Consumer<ArrayList<Task>> callback)
return mTaskList.getTasks(false /* loadKeysOnly */, callback);
执行getTasks时,实际是通过RecentsTaskList的getTasks()来执行的;
@Overridepublic void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot)
mThumbnailCache.updateTaskSnapShot(taskId, snapshot);
for (int i = mThumbnailChangeListeners.size() - 1; i >= 0; i--)
Task task = mThumbnailChangeListeners.get(i).onTaskThumbnailChanged(taskId, snapshot);
if (task != null)
task.thumbnail = snapshot;
当Task的snapshot截取完毕后,会收到onTaskSnapshotChanged()回调,先对snapshot进行缓存,然后执行onTaskThumbnailChanged()通知,在RecentsView里面对thumbnail进行更新;
5、RecentsTaskList.java
获取最近任务列表类
public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
// Kick off task loading in the background
UI_HELPER_EXECUTOR.execute(() ->
if (!mResultsBg.isValidForRequest(requestLoadId, loadKeysOnly))
mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly);
TaskLoadResult loadResult = mResultsBg;
mMainThreadExecutor.execute(() ->
mResultsUi = loadResult;
if (callback != null)
ArrayList<Task> result = copyOf(mResultsUi);
callback.accept(result);
);
);
return requestLoadId;
在getTasks()内部通过loadTasksInBackgroud()来获取TaskLoadResult对象mResultsBg,然后在主线程里面进行回调,最终执行到RecentsView里面的applyLoadPlan()是在主线程里面刷新UI;先看一下loadTasksInBackground()方法:
TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly)
int currentUserId = Process.myUserHandle().getIdentifier();
List<ActivityManager.RecentTaskInfo> rawTasks =
mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
// The raw tasks are given in most-recent to least-recent order, we need to reverse it
Collections.reverse(rawTasks);
;;;;;;;;;;;;;;;;;;;;;;;;;;;
TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
for (ActivityManager.RecentTaskInfo rawTask : rawTasks)
Task.TaskKey taskKey = new Task.TaskKey(rawTask);
Task task;
if (!loadKeysOnly)
boolean isLocked = tmpLockedUsers.get(taskKey.userId);
task = Task.from(taskKey, rawTask, isLocked);
else
task = new Task(taskKey);
allTasks.add(task);
return allTasks;
可以看到,在loadTasksInBackgroud()内部,通过ActivityManagerWrapper的getRecentTasks()来获取rawTasks,然后反向排序,最后将其处理添加到allTasks,然后返回结果;
6.ActivityManagerWrapper.java
SystemUI与SystemServer交互类
public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId)
try
return ActivityTaskManager.getService().getRecentTasks(numTasks,RECENT_IGNORE_UNAVAILABLE, userId).getList();
public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution)
ActivityManager.TaskSnapshot snapshot = null;
try
snapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId, isLowResolution);
catch (RemoteException e)
Log.w(TAG, "Failed to retrieve task snapshot", e);
if (snapshot != null)
return new ThumbnailData(snapshot);
else
return new ThumbnailData();
public boolean startActivityFromRecents(int taskId, ActivityOptions options)
try
Bundle optsBundle = options == null ? null : options.toBundle();
ActivityTaskManager.getService().startActivityFromRecents(taskId, optsBundle);
return true;
catch (Exception e)
return false;
ActivityManagerWrapper提供了跟systemserver交互的接口,相当于Android8.1中的SystemServicesProxy功能
Android系统之路(初识MTK) ------Android11.0添加Recents一键清除最近任务按钮
Android11.0添加Recents一键清除最近任务按钮
今天因为在复测昨天的一个monkey压测并且还没测完,所以打算记录最近做系统开发的一些心得和经验,也记录一下自己的系统开发历程
修改前效果:
修改后的效果:
后期补上…
需要修改的文件列表(注意:各个版本或平台可能要修改的文件不一样,作者源码为非原生,均属于MTK平台)
packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
packages/apps/Launcher3/quickstep/res/layout/overview_actions_container.xml
vendor/mediatek/proprietary/packages/apps/Launcher3/quickstep/res/drawable/clear_all_task.xml
vendor/mediatek/proprietary/packages/apps/Launche
以上是关于Android11 最近任务Recents功能分析,分析的很彻底的主要内容,如果未能解决你的问题,请参考以下文章
Android系统之路(初识MTK) ------Android11.0添加Recents一键清除最近任务按钮