美文网首页Android 源码浅析
Android10.0 最近任务Recents功能分析

Android10.0 最近任务Recents功能分析

作者: 孤街酒客0911 | 来源:发表于2022-08-16 16:03 被阅读0次

    在Android10.0上,Recents功能分布在SystemUI和Launcher3里面集成.

    一.初始化

    跟Android8.1类似,先看初始化入口:

    1.Recents.java

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

    private final RecentsImplementation mImpl
    @Override
    public void start() {
        //加入callback
        mCommandQueue.addCallback(this);
        mImpl.onStart(mContext);
    }
    
    

    RecentsImplementation替代了之前的RecentsImpl,是一个interface,由其实现类OverviewProxyRecentsImpl来执行操作,关于该类的实例化用到了dagger2,不懂的同学可以去学习一下;

    2.OverviewProxyRecentsImpl.java

    private OverviewProxyService mOverviewProxyService;
    @Override
    public void onStart(Context context) {
       
        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
    }
    
    

    根据调用关系,在onStart()里面创建了OverviewProxyService对象,看一下具体实现:

    3.OverviewProxyService.java

    中间类,在该类内部去绑定远端的service:

    @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());
    
       
    
        // Connect to the service
        updateEnabledState();
        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();
        }
       
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return mMyBinder;
    }
    
    

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

    @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

    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;
    }
    
    @BinderThread
    public void onOverviewToggle() {
       
        ActivityManagerWrapper.getInstance()
                    .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
        MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
    }
    
    

    以上就是Recents功能在初始化过程中涉及到的关键类,用一张流程图总结一下:

    image

    二.启动

    前面分析了初始化涉及到的关键类,系统启动后会启动SystemUI进程,然后进行一系列初始化,接下来看一下进入Recents的流程:
    关于手势或Key按键触发这一块逻辑处理跟Android8.1处理是一样的,入口都是在PhoneWindowManager,咱们从Recents接收toggleRecentApps()分析:

    1.Recents.java

    @Override
    public void toggleRecentApps() {
       
        mImpl.toggleRecentApps();
    }
    
    

    2.OverviewProxyRecentsImpl.java

    @Override
    public 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
    @Override
    public void onOverviewToggle() {
        mOverviewCommandHelper.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;
    用一张流程图总结一下:

    image

    三.显示

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

    1.RecentsActivity.java

    Recents显示Activity

    @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

    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;

    @Override
    protected 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);
    }
    
    
       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存储;
    
    public int getTasks(Consumer<ArrayList<Task>> callback) {
        return mTaskList.getTasks(false /* loadKeysOnly */, callback);
    }
    
    

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

    @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

    获取最近任务列表类

    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功能;
      用一张流程图总结显示过程:

    image

    以上就是对Android10.0 Recents功能的分析,功能实现由之前一个进程拆分到两个进程,其他处理基本上保持一致。

    原作者:雷涛赛文

    相关文章

      网友评论

        本文标题:Android10.0 最近任务Recents功能分析

        本文链接:https://www.haomeiwen.com/subject/qjorgrtx.html