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 dividerOptional,

Optional> 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对应如下,用来获取远端服务的应用包名。

>com.android.launcher3/com.android.quickstep.RecentsActivity

从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> 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 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 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> 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> 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 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 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 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功能


企业员工出差补助标准的具体实施细则有哪些?
王者荣耀杨戬永曜之星怎么得