Loading quickstep/src/com/android/quickstep/RecentTasksList.java +50 −65 Original line number Diff line number Diff line Loading @@ -22,35 +22,33 @@ import android.annotation.TargetApi; import android.app.ActivityManager; import android.os.Build; import android.os.Process; import android.util.Log; import android.os.RemoteException; import android.util.SparseBooleanArray; import androidx.annotation.VisibleForTesting; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.LooperExecutor; import com.android.systemui.shared.recents.model.GroupTask; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.KeyguardManagerCompat; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.wm.shell.recents.IRecentTasksListener; import com.android.wm.shell.util.GroupedRecentTaskInfo; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Consumer; /** * Manages the recent task list from the system, caching it as necessary. */ @TargetApi(Build.VERSION_CODES.R) public class RecentTasksList extends TaskStackChangeListener { public class RecentTasksList { private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0); private final KeyguardManagerCompat mKeyguardManager; private final LooperExecutor mMainThreadExecutor; private final ActivityManagerWrapper mActivityManagerWrapper; private final SystemUiProxy mSysUiProxy; // The list change id, increments as the task list changes in the system private int mChangeId; Loading @@ -62,12 +60,17 @@ public class RecentTasksList extends TaskStackChangeListener { private TaskLoadResult mResultsUi = INVALID_RESULT; public RecentTasksList(LooperExecutor mainThreadExecutor, KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) { KeyguardManagerCompat keyguardManager, SystemUiProxy sysUiProxy) { mMainThreadExecutor = mainThreadExecutor; mKeyguardManager = keyguardManager; mChangeId = 1; mActivityManagerWrapper = activityManagerWrapper; TaskStackChangeListeners.getInstance().registerTaskStackListener(this); mSysUiProxy = sysUiProxy; sysUiProxy.registerRecentTasksListener(new IRecentTasksListener.Stub() { @Override public void onRecentTasksChanged() throws RemoteException { mMainThreadExecutor.execute(RecentTasksList.this::onRecentTasksChanged); } }); } @VisibleForTesting Loading @@ -78,10 +81,11 @@ public class RecentTasksList extends TaskStackChangeListener { /** * Fetches the task keys skipping any local cache. */ public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) { public void getTaskKeys(int numTasks, Consumer<ArrayList<GroupTask>> callback) { // Kick off task loading in the background UI_HELPER_EXECUTOR.execute(() -> { ArrayList<Task> tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */); ArrayList<GroupTask> tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */); mMainThreadExecutor.execute(() -> callback.accept(tasks)); }); } Loading @@ -93,14 +97,15 @@ public class RecentTasksList extends TaskStackChangeListener { * @param callback The callback to receive the list of recent tasks * @return The change id of the current task list */ public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) { public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<GroupTask>> callback) { final int requestLoadId = mChangeId; if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) { // The list is up to date, send the callback on the next frame, // so that requestID can be returned first. if (callback != null) { // Copy synchronously as the changeId might change by next frame ArrayList<Task> result = copyOf(mResultsUi); ArrayList<GroupTask> result = copyOf(mResultsUi); mMainThreadExecutor.post(() -> { callback.accept(result); }); Loading @@ -120,7 +125,7 @@ public class RecentTasksList extends TaskStackChangeListener { mLoadingTasksInBackground = false; mResultsUi = loadResult; if (callback != null) { ArrayList<Task> result = copyOf(mResultsUi); ArrayList<GroupTask> result = copyOf(mResultsUi); callback.accept(result); } }); Loading @@ -136,35 +141,7 @@ public class RecentTasksList extends TaskStackChangeListener { return mChangeId == changeId; } @Override public void onTaskStackChanged() { invalidateLoadedTasks(); } @Override public void onRecentTaskListUpdated() { // In some cases immediately after booting, the tasks in the system recent task list may be // loaded, but not in the active task hierarchy in the system. These tasks are displayed in // overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved() // callback (those are for changes to the active tasks), but the task list is still updated, // so we should also invalidate the change id to ensure we load a new list instead of // reusing a stale list. invalidateLoadedTasks(); } @Override public void onTaskRemoved(int taskId) { invalidateLoadedTasks(); } @Override public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { invalidateLoadedTasks(); } @Override public synchronized void onActivityUnpinned() { public void onRecentTasksChanged() { invalidateLoadedTasks(); } Loading @@ -180,8 +157,8 @@ public class RecentTasksList extends TaskStackChangeListener { @VisibleForTesting TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) { int currentUserId = Process.myUserHandle().getIdentifier(); List<ActivityManager.RecentTaskInfo> rawTasks = mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId); ArrayList<GroupedRecentTaskInfo> rawTasks = mSysUiProxy.getRecentTasks(numTasks, currentUserId); // The raw tasks are given in most-recent to least-recent order, we need to reverse it Collections.reverse(rawTasks); Loading @@ -197,45 +174,53 @@ public class RecentTasksList extends TaskStackChangeListener { }; 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); } task.setLastSnapshotData(rawTask); allTasks.add(task); for (GroupedRecentTaskInfo rawTask : rawTasks) { ActivityManager.RecentTaskInfo taskInfo1 = rawTask.mTaskInfo1; ActivityManager.RecentTaskInfo taskInfo2 = rawTask.mTaskInfo2; Task.TaskKey task1Key = new Task.TaskKey(taskInfo1); Task task1 = loadKeysOnly ? new Task(task1Key) : Task.from(task1Key, taskInfo1, tmpLockedUsers.get(task1Key.userId) /* isLocked */); task1.setLastSnapshotData(taskInfo1); Task task2 = null; if (taskInfo2 != null) { Task.TaskKey task2Key = new Task.TaskKey(taskInfo2); task2 = loadKeysOnly ? new Task(task2Key) : Task.from(task2Key, taskInfo2, tmpLockedUsers.get(task2Key.userId) /* isLocked */); task2.setLastSnapshotData(taskInfo2); } allTasks.add(new GroupTask(task1, task2)); } return allTasks; } private ArrayList<Task> copyOf(ArrayList<Task> tasks) { ArrayList<Task> newTasks = new ArrayList<>(); private ArrayList<GroupTask> copyOf(ArrayList<GroupTask> tasks) { ArrayList<GroupTask> newTasks = new ArrayList<>(); for (int i = 0; i < tasks.size(); i++) { newTasks.add(new Task(tasks.get(i))); newTasks.add(new GroupTask(tasks.get(i))); } return newTasks; } private static class TaskLoadResult extends ArrayList<Task> { private static class TaskLoadResult extends ArrayList<GroupTask> { final int mId; final int mRequestId; // If the result was loaded with keysOnly = true final boolean mKeysOnly; TaskLoadResult(int id, boolean keysOnly, int size) { TaskLoadResult(int requestId, boolean keysOnly, int size) { super(size); mId = id; mRequestId = requestId; mKeysOnly = keysOnly; } boolean isValidForRequest(int requestId, boolean loadKeysOnly) { return mId == requestId && (!mKeysOnly || loadKeysOnly); return mRequestId == requestId && (!mKeysOnly || loadKeysOnly); } } } No newline at end of file quickstep/src/com/android/quickstep/RecentsModel.java +11 −9 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.IconProvider.IconChangeListener; import com.android.launcher3.util.Executors.SimpleThreadFactory; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.systemui.shared.recents.model.GroupTask; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; Loading Loading @@ -70,7 +71,7 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL private RecentsModel(Context context) { mContext = context; mTaskList = new RecentTasksList(MAIN_EXECUTOR, new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance()); new KeyguardManagerCompat(context), SystemUiProxy.INSTANCE.get(context)); IconProvider iconProvider = new IconProvider(context); mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider); Loading @@ -95,7 +96,7 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL * always called on the UI thread. * @return the request id associated with this call. */ public int getTasks(Consumer<ArrayList<Task>> callback) { public int getTasks(Consumer<ArrayList<GroupTask>> callback) { return mTaskList.getTasks(false /* loadKeysOnly */, callback); } Loading @@ -120,9 +121,9 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL * @param callback Receives true if task is removed, false otherwise */ public void isTaskRemoved(int taskId, Consumer<Boolean> callback) { mTaskList.getTasks(true /* loadKeysOnly */, (tasks) -> { for (Task task : tasks) { if (task.key.id == taskId) { mTaskList.getTasks(true /* loadKeysOnly */, (taskGroups) -> { for (GroupTask group : taskGroups) { if (group.containsTask(taskId)) { callback.accept(false); return; } Loading @@ -148,14 +149,15 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL ActivityManager.RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask(); int runningTaskId = runningTask != null ? runningTask.id : -1; mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> { for (Task task : tasks) { if (task.key.id == runningTaskId) { mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), taskGroups -> { for (GroupTask group : taskGroups) { if (group.containsTask(runningTaskId)) { // Skip the running task, it's not going to have an up-to-date snapshot by the // time the user next enters overview continue; } mThumbnailCache.updateThumbnailInCache(task); mThumbnailCache.updateThumbnailInCache(group.task1); mThumbnailCache.updateThumbnailInCache(group.task2); } }); } Loading quickstep/src/com/android/quickstep/SystemUiProxy.java +54 −3 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.quickstep; import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.app.PendingIntent; Loading Loading @@ -48,6 +50,9 @@ import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionContro import com.android.wm.shell.onehanded.IOneHanded; import com.android.wm.shell.pip.IPip; import com.android.wm.shell.pip.IPipAnimationListener; import com.android.wm.shell.recents.IRecentTasks; import com.android.wm.shell.recents.IRecentTasksListener; import com.android.wm.shell.util.GroupedRecentTaskInfo; import com.android.wm.shell.splitscreen.ISplitScreen; import com.android.wm.shell.splitscreen.ISplitScreenListener; import com.android.wm.shell.startingsurface.IStartingWindow; Loading @@ -55,6 +60,7 @@ import com.android.wm.shell.startingsurface.IStartingWindowListener; import com.android.wm.shell.transition.IShellTransitions; import java.util.ArrayList; import java.util.Arrays; /** * Holds the reference to SystemUI. Loading @@ -73,6 +79,7 @@ public class SystemUiProxy implements ISystemUiProxy, private IOneHanded mOneHanded; private IShellTransitions mShellTransitions; private IStartingWindow mStartingWindow; private IRecentTasks mRecentTasks; private final DeathRecipient mSystemUiProxyDeathRecipient = () -> { MAIN_EXECUTOR.execute(() -> clearProxy()); }; Loading @@ -83,6 +90,7 @@ public class SystemUiProxy implements ISystemUiProxy, private ISplitScreenListener mPendingSplitScreenListener; private IStartingWindowListener mPendingStartingWindowListener; private ISmartspaceCallback mPendingSmartspaceCallback; private IRecentTasksListener mPendingRecentTasksListener; private final ArrayList<RemoteTransitionCompat> mPendingRemoteTransitions = new ArrayList<>(); // Used to dedupe calls to SystemUI Loading Loading @@ -147,7 +155,7 @@ public class SystemUiProxy implements ISystemUiProxy, public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen, IOneHanded oneHanded, IShellTransitions shellTransitions, IStartingWindow startingWindow, IStartingWindow startingWindow, IRecentTasks recentTasks, ISmartspaceTransitionController smartSpaceTransitionController) { unlinkToDeath(); mSystemUiProxy = proxy; Loading @@ -157,6 +165,7 @@ public class SystemUiProxy implements ISystemUiProxy, mShellTransitions = shellTransitions; mStartingWindow = startingWindow; mSmartspaceTransitionController = smartSpaceTransitionController; mRecentTasks = recentTasks; linkToDeath(); // re-attach the listeners once missing due to setProxy has not been initialized yet. if (mPendingPipAnimationListener != null && mPip != null) { Loading @@ -179,6 +188,10 @@ public class SystemUiProxy implements ISystemUiProxy, registerRemoteTransition(mPendingRemoteTransitions.get(i)); } mPendingRemoteTransitions.clear(); if (mPendingRecentTasksListener != null && mRecentTasks != null) { registerRecentTasksListener(mPendingRecentTasksListener); mPendingRecentTasksListener = null; } if (mPendingSetNavButtonAlpha != null) { mPendingSetNavButtonAlpha.run(); Loading @@ -187,7 +200,7 @@ public class SystemUiProxy implements ISystemUiProxy, } public void clearProxy() { setProxy(null, null, null, null, null, null, null); setProxy(null, null, null, null, null, null, null, null); } // TODO(141886704): Find a way to remove this Loading Loading @@ -759,7 +772,6 @@ public class SystemUiProxy implements ISystemUiProxy, } } // // SmartSpace transitions // Loading @@ -775,4 +787,43 @@ public class SystemUiProxy implements ISystemUiProxy, mPendingSmartspaceCallback = callback; } } // // Recents // public void registerRecentTasksListener(IRecentTasksListener listener) { if (mRecentTasks != null) { try { mRecentTasks.registerRecentTasksListener(listener); } catch (RemoteException e) { Log.w(TAG, "Failed call registerRecentTasksListener", e); } } else { mPendingRecentTasksListener = listener; } } public void unregisterRecentTasksListener(IRecentTasksListener listener) { if (mRecentTasks != null) { try { mRecentTasks.unregisterRecentTasksListener(listener); } catch (RemoteException e) { Log.w(TAG, "Failed call unregisterRecentTasksListener"); } } mPendingRecentTasksListener = null; } public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) { if (mRecentTasks != null) { try { return new ArrayList<>(Arrays.asList(mRecentTasks.getRecentTasks(numTasks, RECENT_IGNORE_UNAVAILABLE, userId))); } catch (RemoteException e) { Log.w(TAG, "Failed call getRecentTasks", e); } } return new ArrayList<>(); } } quickstep/src/com/android/quickstep/TaskThumbnailCache.java +3 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,9 @@ public class TaskThumbnailCache { * Synchronously fetches the thumbnail for the given {@param task} and puts it in the cache. */ public void updateThumbnailInCache(Task task) { if (task == null) { return; } Preconditions.assertUIThread(); // Fetch the thumbnail for this task and put it in the cache if (task.thumbnail == null) { Loading quickstep/src/com/android/quickstep/TouchInteractionService.java +5 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.quickstep.GestureState.DEFAULT_STATE; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; Loading Loading @@ -113,6 +114,7 @@ import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionContro import com.android.systemui.shared.tracing.ProtoTraceable; import com.android.wm.shell.onehanded.IOneHanded; import com.android.wm.shell.pip.IPip; import com.android.wm.shell.recents.IRecentTasks; import com.android.wm.shell.splitscreen.ISplitScreen; import com.android.wm.shell.startingsurface.IStartingWindow; import com.android.wm.shell.transition.IShellTransitions; Loading Loading @@ -171,9 +173,11 @@ public class TouchInteractionService extends Service ISmartspaceTransitionController smartspaceTransitionController = ISmartspaceTransitionController.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER)); IRecentTasks recentTasks = IRecentTasks.Stub.asInterface( bundle.getBinder(KEY_EXTRA_RECENT_TASKS)); MAIN_EXECUTOR.execute(() -> { SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip, splitscreen, onehanded, shellTransitions, startingWindow, splitscreen, onehanded, shellTransitions, startingWindow, recentTasks, smartspaceTransitionController); TouchInteractionService.this.initInputMonitor(); preloadOverview(true /* fromInit */); Loading Loading
quickstep/src/com/android/quickstep/RecentTasksList.java +50 −65 Original line number Diff line number Diff line Loading @@ -22,35 +22,33 @@ import android.annotation.TargetApi; import android.app.ActivityManager; import android.os.Build; import android.os.Process; import android.util.Log; import android.os.RemoteException; import android.util.SparseBooleanArray; import androidx.annotation.VisibleForTesting; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.LooperExecutor; import com.android.systemui.shared.recents.model.GroupTask; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.KeyguardManagerCompat; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.wm.shell.recents.IRecentTasksListener; import com.android.wm.shell.util.GroupedRecentTaskInfo; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Consumer; /** * Manages the recent task list from the system, caching it as necessary. */ @TargetApi(Build.VERSION_CODES.R) public class RecentTasksList extends TaskStackChangeListener { public class RecentTasksList { private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0); private final KeyguardManagerCompat mKeyguardManager; private final LooperExecutor mMainThreadExecutor; private final ActivityManagerWrapper mActivityManagerWrapper; private final SystemUiProxy mSysUiProxy; // The list change id, increments as the task list changes in the system private int mChangeId; Loading @@ -62,12 +60,17 @@ public class RecentTasksList extends TaskStackChangeListener { private TaskLoadResult mResultsUi = INVALID_RESULT; public RecentTasksList(LooperExecutor mainThreadExecutor, KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) { KeyguardManagerCompat keyguardManager, SystemUiProxy sysUiProxy) { mMainThreadExecutor = mainThreadExecutor; mKeyguardManager = keyguardManager; mChangeId = 1; mActivityManagerWrapper = activityManagerWrapper; TaskStackChangeListeners.getInstance().registerTaskStackListener(this); mSysUiProxy = sysUiProxy; sysUiProxy.registerRecentTasksListener(new IRecentTasksListener.Stub() { @Override public void onRecentTasksChanged() throws RemoteException { mMainThreadExecutor.execute(RecentTasksList.this::onRecentTasksChanged); } }); } @VisibleForTesting Loading @@ -78,10 +81,11 @@ public class RecentTasksList extends TaskStackChangeListener { /** * Fetches the task keys skipping any local cache. */ public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) { public void getTaskKeys(int numTasks, Consumer<ArrayList<GroupTask>> callback) { // Kick off task loading in the background UI_HELPER_EXECUTOR.execute(() -> { ArrayList<Task> tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */); ArrayList<GroupTask> tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */); mMainThreadExecutor.execute(() -> callback.accept(tasks)); }); } Loading @@ -93,14 +97,15 @@ public class RecentTasksList extends TaskStackChangeListener { * @param callback The callback to receive the list of recent tasks * @return The change id of the current task list */ public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) { public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<GroupTask>> callback) { final int requestLoadId = mChangeId; if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) { // The list is up to date, send the callback on the next frame, // so that requestID can be returned first. if (callback != null) { // Copy synchronously as the changeId might change by next frame ArrayList<Task> result = copyOf(mResultsUi); ArrayList<GroupTask> result = copyOf(mResultsUi); mMainThreadExecutor.post(() -> { callback.accept(result); }); Loading @@ -120,7 +125,7 @@ public class RecentTasksList extends TaskStackChangeListener { mLoadingTasksInBackground = false; mResultsUi = loadResult; if (callback != null) { ArrayList<Task> result = copyOf(mResultsUi); ArrayList<GroupTask> result = copyOf(mResultsUi); callback.accept(result); } }); Loading @@ -136,35 +141,7 @@ public class RecentTasksList extends TaskStackChangeListener { return mChangeId == changeId; } @Override public void onTaskStackChanged() { invalidateLoadedTasks(); } @Override public void onRecentTaskListUpdated() { // In some cases immediately after booting, the tasks in the system recent task list may be // loaded, but not in the active task hierarchy in the system. These tasks are displayed in // overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved() // callback (those are for changes to the active tasks), but the task list is still updated, // so we should also invalidate the change id to ensure we load a new list instead of // reusing a stale list. invalidateLoadedTasks(); } @Override public void onTaskRemoved(int taskId) { invalidateLoadedTasks(); } @Override public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { invalidateLoadedTasks(); } @Override public synchronized void onActivityUnpinned() { public void onRecentTasksChanged() { invalidateLoadedTasks(); } Loading @@ -180,8 +157,8 @@ public class RecentTasksList extends TaskStackChangeListener { @VisibleForTesting TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) { int currentUserId = Process.myUserHandle().getIdentifier(); List<ActivityManager.RecentTaskInfo> rawTasks = mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId); ArrayList<GroupedRecentTaskInfo> rawTasks = mSysUiProxy.getRecentTasks(numTasks, currentUserId); // The raw tasks are given in most-recent to least-recent order, we need to reverse it Collections.reverse(rawTasks); Loading @@ -197,45 +174,53 @@ public class RecentTasksList extends TaskStackChangeListener { }; 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); } task.setLastSnapshotData(rawTask); allTasks.add(task); for (GroupedRecentTaskInfo rawTask : rawTasks) { ActivityManager.RecentTaskInfo taskInfo1 = rawTask.mTaskInfo1; ActivityManager.RecentTaskInfo taskInfo2 = rawTask.mTaskInfo2; Task.TaskKey task1Key = new Task.TaskKey(taskInfo1); Task task1 = loadKeysOnly ? new Task(task1Key) : Task.from(task1Key, taskInfo1, tmpLockedUsers.get(task1Key.userId) /* isLocked */); task1.setLastSnapshotData(taskInfo1); Task task2 = null; if (taskInfo2 != null) { Task.TaskKey task2Key = new Task.TaskKey(taskInfo2); task2 = loadKeysOnly ? new Task(task2Key) : Task.from(task2Key, taskInfo2, tmpLockedUsers.get(task2Key.userId) /* isLocked */); task2.setLastSnapshotData(taskInfo2); } allTasks.add(new GroupTask(task1, task2)); } return allTasks; } private ArrayList<Task> copyOf(ArrayList<Task> tasks) { ArrayList<Task> newTasks = new ArrayList<>(); private ArrayList<GroupTask> copyOf(ArrayList<GroupTask> tasks) { ArrayList<GroupTask> newTasks = new ArrayList<>(); for (int i = 0; i < tasks.size(); i++) { newTasks.add(new Task(tasks.get(i))); newTasks.add(new GroupTask(tasks.get(i))); } return newTasks; } private static class TaskLoadResult extends ArrayList<Task> { private static class TaskLoadResult extends ArrayList<GroupTask> { final int mId; final int mRequestId; // If the result was loaded with keysOnly = true final boolean mKeysOnly; TaskLoadResult(int id, boolean keysOnly, int size) { TaskLoadResult(int requestId, boolean keysOnly, int size) { super(size); mId = id; mRequestId = requestId; mKeysOnly = keysOnly; } boolean isValidForRequest(int requestId, boolean loadKeysOnly) { return mId == requestId && (!mKeysOnly || loadKeysOnly); return mRequestId == requestId && (!mKeysOnly || loadKeysOnly); } } } No newline at end of file
quickstep/src/com/android/quickstep/RecentsModel.java +11 −9 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import com.android.launcher3.icons.IconProvider; import com.android.launcher3.icons.IconProvider.IconChangeListener; import com.android.launcher3.util.Executors.SimpleThreadFactory; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.systemui.shared.recents.model.GroupTask; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; Loading Loading @@ -70,7 +71,7 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL private RecentsModel(Context context) { mContext = context; mTaskList = new RecentTasksList(MAIN_EXECUTOR, new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance()); new KeyguardManagerCompat(context), SystemUiProxy.INSTANCE.get(context)); IconProvider iconProvider = new IconProvider(context); mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider); Loading @@ -95,7 +96,7 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL * always called on the UI thread. * @return the request id associated with this call. */ public int getTasks(Consumer<ArrayList<Task>> callback) { public int getTasks(Consumer<ArrayList<GroupTask>> callback) { return mTaskList.getTasks(false /* loadKeysOnly */, callback); } Loading @@ -120,9 +121,9 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL * @param callback Receives true if task is removed, false otherwise */ public void isTaskRemoved(int taskId, Consumer<Boolean> callback) { mTaskList.getTasks(true /* loadKeysOnly */, (tasks) -> { for (Task task : tasks) { if (task.key.id == taskId) { mTaskList.getTasks(true /* loadKeysOnly */, (taskGroups) -> { for (GroupTask group : taskGroups) { if (group.containsTask(taskId)) { callback.accept(false); return; } Loading @@ -148,14 +149,15 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL ActivityManager.RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask(); int runningTaskId = runningTask != null ? runningTask.id : -1; mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> { for (Task task : tasks) { if (task.key.id == runningTaskId) { mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), taskGroups -> { for (GroupTask group : taskGroups) { if (group.containsTask(runningTaskId)) { // Skip the running task, it's not going to have an up-to-date snapshot by the // time the user next enters overview continue; } mThumbnailCache.updateThumbnailInCache(task); mThumbnailCache.updateThumbnailInCache(group.task1); mThumbnailCache.updateThumbnailInCache(group.task2); } }); } Loading
quickstep/src/com/android/quickstep/SystemUiProxy.java +54 −3 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.quickstep; import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.app.PendingIntent; Loading Loading @@ -48,6 +50,9 @@ import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionContro import com.android.wm.shell.onehanded.IOneHanded; import com.android.wm.shell.pip.IPip; import com.android.wm.shell.pip.IPipAnimationListener; import com.android.wm.shell.recents.IRecentTasks; import com.android.wm.shell.recents.IRecentTasksListener; import com.android.wm.shell.util.GroupedRecentTaskInfo; import com.android.wm.shell.splitscreen.ISplitScreen; import com.android.wm.shell.splitscreen.ISplitScreenListener; import com.android.wm.shell.startingsurface.IStartingWindow; Loading @@ -55,6 +60,7 @@ import com.android.wm.shell.startingsurface.IStartingWindowListener; import com.android.wm.shell.transition.IShellTransitions; import java.util.ArrayList; import java.util.Arrays; /** * Holds the reference to SystemUI. Loading @@ -73,6 +79,7 @@ public class SystemUiProxy implements ISystemUiProxy, private IOneHanded mOneHanded; private IShellTransitions mShellTransitions; private IStartingWindow mStartingWindow; private IRecentTasks mRecentTasks; private final DeathRecipient mSystemUiProxyDeathRecipient = () -> { MAIN_EXECUTOR.execute(() -> clearProxy()); }; Loading @@ -83,6 +90,7 @@ public class SystemUiProxy implements ISystemUiProxy, private ISplitScreenListener mPendingSplitScreenListener; private IStartingWindowListener mPendingStartingWindowListener; private ISmartspaceCallback mPendingSmartspaceCallback; private IRecentTasksListener mPendingRecentTasksListener; private final ArrayList<RemoteTransitionCompat> mPendingRemoteTransitions = new ArrayList<>(); // Used to dedupe calls to SystemUI Loading Loading @@ -147,7 +155,7 @@ public class SystemUiProxy implements ISystemUiProxy, public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen, IOneHanded oneHanded, IShellTransitions shellTransitions, IStartingWindow startingWindow, IStartingWindow startingWindow, IRecentTasks recentTasks, ISmartspaceTransitionController smartSpaceTransitionController) { unlinkToDeath(); mSystemUiProxy = proxy; Loading @@ -157,6 +165,7 @@ public class SystemUiProxy implements ISystemUiProxy, mShellTransitions = shellTransitions; mStartingWindow = startingWindow; mSmartspaceTransitionController = smartSpaceTransitionController; mRecentTasks = recentTasks; linkToDeath(); // re-attach the listeners once missing due to setProxy has not been initialized yet. if (mPendingPipAnimationListener != null && mPip != null) { Loading @@ -179,6 +188,10 @@ public class SystemUiProxy implements ISystemUiProxy, registerRemoteTransition(mPendingRemoteTransitions.get(i)); } mPendingRemoteTransitions.clear(); if (mPendingRecentTasksListener != null && mRecentTasks != null) { registerRecentTasksListener(mPendingRecentTasksListener); mPendingRecentTasksListener = null; } if (mPendingSetNavButtonAlpha != null) { mPendingSetNavButtonAlpha.run(); Loading @@ -187,7 +200,7 @@ public class SystemUiProxy implements ISystemUiProxy, } public void clearProxy() { setProxy(null, null, null, null, null, null, null); setProxy(null, null, null, null, null, null, null, null); } // TODO(141886704): Find a way to remove this Loading Loading @@ -759,7 +772,6 @@ public class SystemUiProxy implements ISystemUiProxy, } } // // SmartSpace transitions // Loading @@ -775,4 +787,43 @@ public class SystemUiProxy implements ISystemUiProxy, mPendingSmartspaceCallback = callback; } } // // Recents // public void registerRecentTasksListener(IRecentTasksListener listener) { if (mRecentTasks != null) { try { mRecentTasks.registerRecentTasksListener(listener); } catch (RemoteException e) { Log.w(TAG, "Failed call registerRecentTasksListener", e); } } else { mPendingRecentTasksListener = listener; } } public void unregisterRecentTasksListener(IRecentTasksListener listener) { if (mRecentTasks != null) { try { mRecentTasks.unregisterRecentTasksListener(listener); } catch (RemoteException e) { Log.w(TAG, "Failed call unregisterRecentTasksListener"); } } mPendingRecentTasksListener = null; } public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) { if (mRecentTasks != null) { try { return new ArrayList<>(Arrays.asList(mRecentTasks.getRecentTasks(numTasks, RECENT_IGNORE_UNAVAILABLE, userId))); } catch (RemoteException e) { Log.w(TAG, "Failed call getRecentTasks", e); } } return new ArrayList<>(); } }
quickstep/src/com/android/quickstep/TaskThumbnailCache.java +3 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,9 @@ public class TaskThumbnailCache { * Synchronously fetches the thumbnail for the given {@param task} and puts it in the cache. */ public void updateThumbnailInCache(Task task) { if (task == null) { return; } Preconditions.assertUIThread(); // Fetch the thumbnail for this task and put it in the cache if (task.thumbnail == null) { Loading
quickstep/src/com/android/quickstep/TouchInteractionService.java +5 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.quickstep.GestureState.DEFAULT_STATE; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; Loading Loading @@ -113,6 +114,7 @@ import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionContro import com.android.systemui.shared.tracing.ProtoTraceable; import com.android.wm.shell.onehanded.IOneHanded; import com.android.wm.shell.pip.IPip; import com.android.wm.shell.recents.IRecentTasks; import com.android.wm.shell.splitscreen.ISplitScreen; import com.android.wm.shell.startingsurface.IStartingWindow; import com.android.wm.shell.transition.IShellTransitions; Loading Loading @@ -171,9 +173,11 @@ public class TouchInteractionService extends Service ISmartspaceTransitionController smartspaceTransitionController = ISmartspaceTransitionController.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER)); IRecentTasks recentTasks = IRecentTasks.Stub.asInterface( bundle.getBinder(KEY_EXTRA_RECENT_TASKS)); MAIN_EXECUTOR.execute(() -> { SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip, splitscreen, onehanded, shellTransitions, startingWindow, splitscreen, onehanded, shellTransitions, startingWindow, recentTasks, smartspaceTransitionController); TouchInteractionService.this.initInputMonitor(); preloadOverview(true /* fromInit */); Loading