在Android10.0上,Recents功能分布在SystemUI和Launcher3里面集成.
一.初始化 跟Android8.1类似,先看初始化入口:
1.Recents.java Recents继承SystemUI,进程启动后会在Dependency里面通过@Inject进行初始化,然后在SystemUIService里面调用SystemUIApplication的startServicesIfNeeded()里面进行启动:frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java
1 2 3 4 5 6 7 private final RecentsImplementation mImpl@Override public void start () { mCommandQueue.addCallback(this ); mImpl.onStart(mContext); }
RecentsImplementation替代了之前的RecentsImpl,是一个interface,由其实现类OverviewProxyRecentsImpl来执行操作,关于该类的实例化用到了dagger2,不懂的同学可以去学习一下;
2.OverviewProxyRecentsImpl.java frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
1 2 3 4 5 6 private OverviewProxyService mOverviewProxyService;@Override public void onStart (Context context) { mOverviewProxyService = Dependency.get(OverviewProxyService.class); }
根据调用关系,在onStart()里面创建了OverviewProxyService对象,看一下具体实现:
3.OverviewProxyService.java 中间类,在该类内部去绑定远端的service:frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Inject public 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()); updateEnabledState(); startConnectionToCurrentUser(); }
1 2 3 4 5 6 7 public void startConnectionToCurrentUser () { if (mHandler.getLooper() != Looper.myLooper()) { mHandler.post(mConnectionRunnable); } else { internalConnectToCurrentUser(); } }
1 2 3 4 5 6 7 8 9 10 11 12 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())); } }
1 2 3 4 5 6 7 8 9 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对应如下,用来获取远端服务的应用包名:
1 2 <string name="config_recentsComponentName" translatable="false" >com.android.launcher3/com.android.quickstep.RecentsActivity</string>
从ComponentName可以看到,被bind的service是在Launcher3里面,接下来一起看一下对应的远端Service;
4.TouchInteractionService.java packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java Launcher3内的入口类,通过该类来调用相关逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 private final IBinder mMyBinder = new IOverviewProxy .Stub() { @BinderThread @Override public void onOverviewToggle () { mOverviewCommandHelper.onOverviewToggle(); } } @Override public IBinder onBind (Intent intent) { return mMyBinder; }
可以看到,TouchInteractionService里面创建了IOverviewProxy.Stub实例,然后在onBind()返回; TouchInteractionService是一个Service,在onCreate()里面进行了一些初始化相关的调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override public void onCreate () { super .onCreate(); mDeviceState.runOnUserUnlocked(this ::onUserUnlocked); sConnected = true ; } @UiThread public void onUserUnlocked () { mOverviewComponentObserver = new OverviewComponentObserver (this , mDeviceState); mOverviewCommandHelper = new OverviewCommandHelper (this , mDeviceState, mOverviewComponentObserver); }
可以看到,在TouchInteractionService启动后,会创建OverviewComponentObserver实例和OverviewCommandHelper实例,一起看一下这两个类的实现:
5.OverviewComponentObserver.java packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
1 2 3 4 5 6 7 8 9 10 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():
1 2 3 4 5 6 7 private void updateOverviewTargets () { mActivityInterface = FallbackActivityInterface.INSTANCE; mIsHomeAndOverviewSame = false ; mOverviewIntent = mFallbackIntent; }
在该方法内部,会将mFallbackIntent赋值给mOverviewIntent,后续启动Recents会用到mOverviewIntent;
6.OverviewCommandHelper.java packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java 启动Recents的直接入口类,最终实现了onOverviewToggle():
1 2 3 4 5 6 7 8 9 10 11 12 13 public OverviewCommandHelper (Context context, RecentsAnimationDeviceState deviceState, OverviewComponentObserver observer) { mRecentsModel = RecentsModel.INSTANCE.get(mContext); mOverviewComponentObserver = observer; } @BinderThread public void onOverviewToggle () { ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); MAIN_EXECUTOR.execute(new RecentsActivityCommand <>()); }
以上就是Recents功能在初始化过程中涉及到的关键类,用一张流程图总结一下:
二.启动 前面分析了初始化涉及到的关键类,系统启动后会启动SystemUI进程,然后进行一系列初始化,接下来看一下进入Recents的流程: 关于手势或Key按键触发这一块逻辑处理跟Android8.1处理是一样的,入口都是在PhoneWindowManager,咱们从Recents接收toggleRecentApps()分析:
1.Recents.java frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java
1 2 3 4 5 @Override public void toggleRecentApps () { mImpl.toggleRecentApps(); }
2.OverviewProxyRecentsImpl.java frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override public void toggleRecentApps () { 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内部会通过OverviewProxyService的getProxy()来获取到Launcher3端实现的IOveriewProxy对象引用,然后调用onOverviewToggle()方法:
3.TouchInteractionService.java packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
1 2 3 4 5 @BinderThread @Override public void onOverviewToggle () { mOverviewCommandHelper.onOverviewToggle(); }
4.OverviewCommandHelper.java packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
1 2 3 4 5 6 @BinderThread public void onOverviewToggle () { ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); MAIN_EXECUTOR.execute(new RecentsActivityCommand <>()); }
可以看到,在执行onOverviewToggle()后,实际上是通过Executoe执行了RecentsActivityCommand:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 private class RecentsActivityCommand <T extends StatefulActivity <?>> implements Runnable { public RecentsActivityCommand () { mActivityInterface = mOverviewComponentObserver.getActivityInterface(); mRecentsModel.getTasks(null ); } @Override public void run () { 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 frameworks/base/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java Recents显示Activity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override protected 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 frameworks/base/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java Recents显示主View
1 2 3 4 5 6 7 8 9 10 11 12 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 , 10 ); }
可以看到,在构造方法内部,获取了RecentsModel实例,创建了ViewPool实例mTaskViewPool,该mTaskViewPool存储TaskView,对应的layout为 R.layout.task,最大数量为20;
1 2 3 4 5 6 7 8 @Override protected void onAttachedToWindow () { super .onAttachedToWindow(); updateTaskStackListenerState(); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this ); }
在RecentsView显示时会回调onAttachedToWindow(),在内部执行了updateTaskStackListenerState(),然后做了一些注册回调操作,当有变化时,会进行回调通知来更新UI;
1 2 3 4 5 6 7 8 9 10 private void updateTaskStackListenerState () { boolean handleTaskStackChanges = mOverviewStateEnabled && isAttachedToWindow() && getWindowVisibility() == VISIBLE; if (handleTaskStackChanges != mHandleTaskStackChanges) { mHandleTaskStackChanges = handleTaskStackChanges; if (handleTaskStackChanges) { reloadIfNeeded(); } } }
在updateTaskStackListenerState()内部会进行一系列条件判断来确定是否执行reloadIfNeeded(),当首次进入时会执行reloadIfNeeded():
1 2 3 4 5 public void reloadIfNeeded () { if (!mModel.isTaskListValid(mTaskListChangeId)) { mTaskListChangeId = mModel.getTasks(this ::applyLoadPlan); } }
通过RecentsModel的getTasks()来获取任务列表,然后回到applyLoadPlan(),getTasks()逻辑在后面进行分析,先看一下applyLoadPlan()方法的执行逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 protected void applyLoadPlan (ArrayList<Task> tasks) { unloadVisibleTaskData(); final int requiredTaskCount = tasks.size(); if (getTaskViewCount() != requiredTaskCount) { for (int i = getTaskViewCount(); i < requiredTaskCount; i++) { addView(mTaskViewPool.getView()); } if (requiredTaskCount > 0 ) { addView(mClearAllButton); } } 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()内部,主要执行了四项工作:
unloadVisibleTaskData():将现有visible的task数据进行置空;
根据task数量(首次进入)进行addView,TaskView通过mTaskViewPool的getView()进行获取,最后添加clearAllButton;
对添加完的TaskView进行bind()操作,将对应的task存在TaskView内部,类似setTag()功能;
执行resetTaskVisuals()来刷新加载数据;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public void resetTaskVisuals () { loadVisibleTaskData(); } public void loadVisibleTaskData () { 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) { continue ; } if (!mHasVisibleTaskData.get(task.key.id)) { taskView.onTaskListVisibilityChanged(true ); } mHasVisibleTaskData.put(task.key.id, visible); } } }
最终在loadVisibleTaskData()里面通过TaskView的onTaskVisibilityChanged(true)来加载数据;
3.TaskView.java Recents列表中Task对应的显示Viewframeworks/base/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskView.java
1 2 3 4 public void bind (Task task, RecentsOrientedState orientedState) { mTask = task; mSnapshotView.bind(task); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public void onTaskListVisibilityChanged (boolean visible) { if (mTask == null ) { return ; } cancelPendingLoadTasks(); if (visible) { 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 ); mTask.thumbnail = null ; } }
在onTaskListVisibilityChanged()内部,当visible为true时,执行mSnapshotView.setThumbnail()和setIcon()分别来加载缩略图和icon;当visible为false时,将其置空;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public TaskView (Context context, AttributeSet attrs, int defStyleAttr) { super (context, attrs, defStyleAttr); setOnClickListener((view) -> { if (getTask() == null ) { return ; } launchTask(true ); }); } public void launchTask (boolean animate) { launchTask(animate, false ); } 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数据获取功能管理类packages/apps/Launcher3/quickstep/src/com/android/quickstep/RecentsModel.java
1 2 3 4 5 6 7 8 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 2 3 4 5 RecentsModel继承了TaskStackChangeListener,在构造方法内部初始化了RecentsTaskList、TaskIconCache和TaskThumbnailCache实例,注册了registerTaskStackListener回调;分别来获取最近任务列表、获取Task对应的Icon和, RecentsTaskList:获取最近任务列表; TaskIconCache:获取Task对应的icon,并进行缓存; TaskThumbnailCache:获取Task对应的thumbnailData,并进行缓存; 与Android8.1 不同的是,8.1 上在获取最近任务列表后会获取任务对应的Thumbnail和Icon,最终封装成Task,在显示时直接通过Task.thumbnail和Task.icon就可以直接显示;11 上会通过TaskIconCache和TaskThumbnailCache进行分别存储管理,首次显示或有新的任务,需要通过TaskIconCache和TaskThumbnailCache执行对应的request去获取并进行cache存储;
1 2 3 public int getTasks (Consumer<ArrayList<Task>> callback) { return mTaskList.getTasks(false , callback); }
执行getTasks时,实际是通过RecentsTaskList的getTasks()来执行的;
1 2 3 4 5 6 7 8 9 10 @Override public 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 获取最近任务列表类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public synchronized int getTasks (boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) { 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()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 TaskLoadResult loadTasksInBackground (int numTasks, int requestId, boolean loadKeysOnly) { int currentUserId = Process.myUserHandle().getIdentifier(); List<ActivityManager.RecentTaskInfo> rawTasks = mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId); 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交互类frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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功能; 用一张流程图总结显示过程:
以上就是对Android10.0 Recents功能的分析,功能实现由之前一个进程拆分到两个进程,其他处理基本上保持一致。
本文链接: http://longzhiye.top/2023/12/02/2023-12-02/