Android11 最近任务Recents功能分析,分析的很彻底

时间:2025-01-28 08:44:42

Android11 最近任务Recents功能分析

一、初始化
1、

Recents继承SystemUI,进程启动后会在Dependency里面通过@Inject进行初始化,然后在SystemUIService里面调用SystemUIApplication的startServicesIfNeeded()里面进行启动:

private final RecentsImplementation mImpl
@Overridepublic void start() {
    //加入callback
    (this);
    (mContext);}

RecentsImplementation替代了之前的RecentsImpl,是一个interface,由其实现类OverviewProxyRecentsImpl来执行操作

2、
private OverviewProxyService mOverviewProxyService;@Overridepublic void onStart(Context context) {
    ;;;;;;;;;;;;;;;;;;;;;;
    mOverviewProxyService = ();}

这个是根据调用关系,在onStart里面创建了OverviewProxyService对象。

3、

中间类,在该类内部去绑定远端的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 = ((
            .config_recentsComponentName));
    mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
            .setPackage(());
        

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;

    // Connect to the service
    updateEnabledState();
    startConnectionToCurrentUser();}

在接着去查看startConnectionToCurrentUser方法。

public void startConnectionToCurrentUser() {
    if (() != ()) {
        (mConnectionRunnable);
    } else {
        internalConnectToCurrentUser();
    }}

一步步往下走

private void internalConnectToCurrentUser() {
    ;;;;;;;;;;;;;;;;;;;;;;;;;;
    Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
                .setPackage(());
    try {
        mBound = (launcherServiceIntent,
                    mOverviewServiceConnection,
                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                    (getCurrentUserId()));
        }
    ;;;;;;;;;;;;;;;;;;;;;;;;;}

又调用了

private IOverviewProxy mOverviewProxy;private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        ;;;;;;;;;;;;;;;;;;;;
        mOverviewProxy = (service);
        ;;;;;;;;;;;;;;;;;;;;;;;;
    }}

跟随调用关系来看,在构造方法内部,会去执行startConnectionToCurrentUser来调用bindServiceAsUser()去启动service,在onServiceConnected中,通过(service)来获取IOverviewProxy实例,后续会用到;Service对应的Intent为.QUICKSTEP_SERVICE,.config_recentsComponentName对应如下,用来获取远端服务的应用包名。

<string name="config_recentsComponentName" translatable="false"
        >.launcher3/</string>

从ComponentName可以看到,被bind的service是在Launcher3里面,接下来一起看一下对应的远端Service;

4、

Launcher3内的入口类,通过该类来调用相关逻辑

private final IBinder mMyBinder = new () {
    ;;;;;;;;;;;;;;;;;;;;;;;;;;
    @BinderThread
    @Override
    public void onOverviewToggle() {
        ();
    }
    ;;;;;;;;;;;;;;;;;;;}

@Overridepublic IBinder onBind(Intent intent) {
    return mMyBinder;}

可以看到,TouchInteractionService里面创建了实例,然后在onBind()返回;
TouchInteractionService是一个Service,在onCreate()里面进行了一些初始化相关的调用


@Overridepublic void onCreate() {
    ();
    ;;;;;;;;;;;;;;;;;;;;
    (this::onUserUnlocked);
    ;;;;;;;;;;;;;;;;;;;;

    sConnected = true;}

@UiThreadpublic void onUserUnlocked() {
    ;;;;;;;;;;;;;
    mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
    mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState,
                mOverviewComponentObserver);
    ;;;;;;;;;;;;;;;;;;;;;;;;}

可以看到,在TouchInteractionService启动后,会创建OverviewComponentObserver实例和OverviewCommandHelper实例,一起看一下这两个类的实现

5、
public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) {
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ComponentName fallbackComponent = new ComponentName(mContext, );
    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 = ;
    mIsHomeAndOverviewSame = false;
    mOverviewIntent = mFallbackIntent;
    ;;;;;;;;;;;;;;;;;}

在这个方法的内部,会将mFallbackIntent赋值给mOverviewIntent,后续启动Recents就会用到mOverviewIntent。

6、

启动Recents的直接入口类,最终会去实现onOverviewToggle

public OverviewCommandHelper(Context context, RecentsAnimationDeviceState deviceState,
            OverviewComponentObserver observer) {
    ;;;;;;;;;;;;;;;;;;;;;
    mRecentsModel = (mContext);
    mOverviewComponentObserver = observer;}

@BinderThreadpublic void onOverviewToggle() {
    ;;;;;;;;;;;;;;;;;;;;
    ()
                .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
    MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());}

二、启动

入口都是在PhoneWindowManager,直接从接收来分析接收类toggleRecentApps

1、
@Overridepublic void toggleRecentApps() {
    ;;;;;;;;;;;;;;;;;;;
    ();}

这里启动了这个类,去进行查看

2、
@Overridepublic void toggleRecentApps() {
    // If connected to launcher service, let it handle the toggle logic
    IOverviewProxy overviewProxy = ();
    if (overviewProxy != null) {
        final Runnable toggleRecents = () -> {
            try {
                if (() != null) {
                    ().onOverviewToggle();
                    ();
                }
            } catch (RemoteException e) {
                (TAG, "Cannot send toggle recents through proxy service.", e);
            }
        };
        //启动runnable
    }}

这里就是在runnable内部会通过OverviewProxyService的getProxy()来获取到Launcher3实现的IOveriewProxy对象引用,然后调用onOverviewToggle()方法。

3、
@BinderThread@Overridepublic void onOverviewToggle() {
    ();}

继续往下走,可以看见启动OverviewCommandHelper中的onOverviewToggle

4、
@BinderThread
public void onOverviewToggle() {

   ()
                .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 = ();
        ;;;;;;;;;;;;;;

        //预加载,Android8.1也有相同的逻辑
        (null);
    }

    @Override
     public void run() {
         ;;;;;;;;;;;;;;;;;;;;;;;;;
         // Otherwise, start overview.
         mListener = (this::onActivityReady);
         ((),
                    new RemoteAnimationProvider() {
                        @Override
                        public AnimatorSet createWindowAnimation(
                                RemoteAnimationTargetCompat[] appTargets,
                                RemoteAnimationTargetCompat[] wallpaperTargets) {
                            return (appTargets,
                                    wallpaperTargets);
                        }
                    }, mContext, MAIN_EXECUTOR.getHandler(),
                    ());
        }

可以看到,最终是通过registerAndStartActivity()来启动了intent,前面分析到()对应的就是mFallbackIntent,最终启动了RecentsActivity;

三、显示

在启动RecentsActivity后,会显示最近任务列表,看一下具体工作流程

1、

Recents显示Activity

@Overrideprotected void onCreate(Bundle savedInstanceState) {
    (savedInstanceState);
    ;;;;;;;;;;;;;;;;;;;;;;;;;;
    setupViews();
    ;;;;;;;;;;;;;;;;;;;;;;;;}

protected void setupViews() {
    inflateRootView(.fallback_recents_activity);
    setContentView(getRootView());
    mDragLayer = findViewById(.drag_layer);
    mFallbackRecentsView = findViewById(.overview_panel);
    mActionsView = findViewById(.overview_actions_view);

    ();
    (mActionsView);}

RecentsActivity继承了StatefulActivity,有些方法实现是在父类里面执行的,在onCreate()里面执行setupViews(),初始化了FallbackRecentsView,FallbackRecentsView继承了RecentsView,主要逻辑都是在RecentsView里面实现的,直接看RecentsView的实现逻辑:

2、

Recents显示主View

public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
            BaseActivityInterface sizeStrategy) {
    super(context, attrs, defStyleAttr);
    ;;;;;;;;;;;;;;;;;;;;;;;
    mModel = (context);
        
    mClearAllButton = (ClearAllButton) (context)
                .inflate(.overview_clear_all_button, this, false);
    (this::dismissAllTasks);
    mTaskViewPool = new ViewPool<>(context, this, , 20 /* max size */,
                10 /* initial size */);

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;}

可以看见,在构造方法内部,获取了RecentsModel实例,创建了ViewPool实例mTaskViewPool,该mTaskViewPool存储TaskView,对应的layout为 ,最大数量为20;

@Overrideprotected void onAttachedToWindow() {
    ();
    updateTaskStackListenerState();
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ().registerTaskStackListener(mTaskStackListener);
    //当snapshot更新时,会进行回调刷新UI
    (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 (!(mTaskListChangeId)) {
        mTaskListChangeId = (this::applyLoadPlan);
    }}

通过RecentsModel的getTasks()来获取任务列表,然后回到applyLoadPlan(),getTasks()逻辑在后面进行分析,先看一下applyLoadPlan()方法的执行逻辑:

protected void applyLoadPlan(ArrayList<Task> tasks) {
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    // Unload existing visible task data
    unloadVisibleTaskData();

    final int requiredTaskCount = ();
    if (getTaskViewCount() != requiredTaskCount) {
        ;;;;;;;;;;;;
        for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
            addView(());
        }
        ;;;;;;;;;;;;;;;;;;;
        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 = (i);
        final TaskView taskView = (TaskView) getChildAt(pageIndex);
        (task, mOrientationState);
    }
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    resetTaskVisuals();
    ;;;;;;;;;;;;;;;
    }

在applyLoadPlan()内部,主要执行了四项工作:
():将现有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 = ();
         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 (!()) {
                 (true /* visible */);
             }
             (, visible);
         }
    }}

最终在loadVisibleTaskData()里面通过TaskView的onTaskVisibilityChanged(true)来加载数据;

3、

Recents列表中Task对应的显示View

public void bind(Task task, RecentsOrientedState orientedState) {
    mTask = task;
    (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 = (getContext());
        TaskThumbnailCache thumbnailCache = ();
        TaskIconCache iconCache = ();
        mThumbnailLoadRequest = (
                    mTask, thumbnail -> (mTask, thumbnail));
        mIconLoadRequest = (mTask,
                    (task) -> {
                        setIcon();
                        if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
                            getRecentsView().updateLiveTileIcon();
                        }
                        (mTask);
                    });
        } else {
            (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)
             = null;
        }}

在onTaskListVisibilityChanged()内部,当visible为true时,执行()和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) {
        ;;;;;;;;;;;;;;
        ().startActivityFromRecentsAsync(,
                    opts, resultCallback, resultCallbackHandler);
        ;;;;;;;;;;;;;;;;;;;;
        getRecentsView().onTaskLaunched(mTask);
    }}

在TaskView内部设置了点击事件监听,当点击后会执行launchTask,最终会调用到ActivityManagerWrapper的startActivityFromRecentsAsync()来快速切换到对应的任务

4、

Recents数据获取功能管理类

private RecentsModel(Context context) {
    mContext = context;
    mTaskList = new RecentTasksList(MAIN_EXECUTOR,
                new KeyguardManagerCompat(context), ());
    mIconCache = new TaskIconCache(context, looper);
    mThumbnailCache = new TaskThumbnailCache(context, looper);

   ().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 (false /* loadKeysOnly */, callback);}

执行getTasks时,实际是通过RecentsTaskList的getTasks()来执行的;

@Overridepublic void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
    (taskId, snapshot);

    for (int i = () - 1; i >= 0; i--) {
        Task task = (i).onTaskThumbnailChanged(taskId, snapshot);
        if (task != null) {
             = snapshot;
        }
    }}

当Task的snapshot截取完毕后,会收到onTaskSnapshotChanged()回调,先对snapshot进行缓存,然后执行onTaskThumbnailChanged()通知,在RecentsView里面对thumbnail进行更新;

5、

获取最近任务列表类

public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    // Kick off task loading in the background
    UI_HELPER_EXECUTOR.execute(() -> {
       if (!(requestLoadId, loadKeysOnly)) {
            mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly);
       }
       TaskLoadResult loadResult = mResultsBg;
       (() -> {
           mResultsUi = loadResult;
           if (callback != null) {
               ArrayList<Task> result = copyOf(mResultsUi);
               (result);
           }
      });
    });

   return requestLoadId;}

在getTasks()内部通过loadTasksInBackgroud()来获取TaskLoadResult对象mResultsBg,然后在主线程里面进行回调,最终执行到RecentsView里面的applyLoadPlan()是在主线程里面刷新UI;先看一下loadTasksInBackground()方法:

TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) {
    int currentUserId = ().getIdentifier();
    List<> rawTasks =
                (numTasks, currentUserId);
    // The raw tasks are given in most-recent to least-recent order, we need to reverse it
    (rawTasks);

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;

    TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, ());
    for ( rawTask : rawTasks) {
         taskKey = new (rawTask);
        Task task;
        if (!loadKeysOnly) {
            boolean isLocked = ();
            task = (taskKey, rawTask, isLocked);
        } else {
            task = new Task(taskKey);
        }
        (task);
    }

    return allTasks;}

可以看到,在loadTasksInBackgroud()内部,通过ActivityManagerWrapper的getRecentTasks()来获取rawTasks,然后反向排序,最后将其处理添加到allTasks,然后返回结果;

SystemUI与SystemServer交互类

public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
    try {
       return ().getRecentTasks(numTasks,RECENT_IGNORE_UNAVAILABLE, userId).getList();
    }}

public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
     snapshot = null;
    try {
        snapshot = ().getTaskSnapshot(taskId, isLowResolution);
    } catch (RemoteException e) {
        (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 : ();
        ().startActivityFromRecents(taskId, optsBundle);
        return true;
    } catch (Exception e) {
        return false;
    }
 }

ActivityManagerWrapper提供了跟systemserver交互的接口,相当于Android8.1中的SystemServicesProxy功能