Only stabilize tasks during quick switch session
- A stabilization session starts when going to a new task via a quick switch - A stabilization session ends after 5 seconds on the same task or when completing a gesture to go to home or overview - We track the system task order and copy it for the duration of the stabilization session - After the session ends, we switch back to the system task order - Remove ENABLE_TASK_STABILIZATION flag (and also QUICK_SWITCH) Bug: 111926330 Change-Id: I2c18dff2d20ad02b73a4935ac534e9fc9f5f49c0
This commit is contained in:
parent
5616670a5a
commit
60ac5d2b34
|
@ -73,6 +73,14 @@ public class RecentTasksList extends TaskStackChangeListener {
|
|||
});
|
||||
}
|
||||
|
||||
public void startStabilizationSession() {
|
||||
mStabilizer.startStabilizationSession();
|
||||
}
|
||||
|
||||
public void endStabilizationSession() {
|
||||
mStabilizer.endStabilizationSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously fetches the list of recent tasks, reusing cached list if available.
|
||||
*
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentCallbacks2;
|
||||
|
@ -28,6 +26,7 @@ import android.os.Process;
|
|||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
|
@ -35,11 +34,14 @@ import com.android.systemui.shared.recents.ISystemUiProxy;
|
|||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
|
||||
|
||||
/**
|
||||
* Singleton class to load and manage recents model.
|
||||
*/
|
||||
|
@ -90,6 +92,14 @@ public class RecentsModel extends TaskStackChangeListener {
|
|||
return mThumbnailCache;
|
||||
}
|
||||
|
||||
public void startStabilizationSession() {
|
||||
mTaskList.startStabilizationSession();
|
||||
}
|
||||
|
||||
public void endStabilizationSession() {
|
||||
mTaskList.endStabilizationSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the list of recent tasks.
|
||||
*
|
||||
|
|
|
@ -15,13 +15,10 @@
|
|||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASK_STABILIZER;
|
||||
|
||||
import android.app.ActivityManager.RecentTaskInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
@ -33,98 +30,77 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Keeps the task list stable during quick switch gestures. So if you swipe right to switch from app
|
||||
* A to B, you can then swipe right again to get to app C or left to get back to A.
|
||||
*/
|
||||
public class TaskListStabilizer {
|
||||
|
||||
private static final long TASK_CACHE_TIMEOUT_MS = 5000;
|
||||
|
||||
private static final int INVALID_TASK_ID = -1;
|
||||
|
||||
private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onTaskCreated(int taskId, ComponentName componentName) {
|
||||
onTaskCreatedInternal(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskMovedToFront(int taskId) {
|
||||
onTaskMovedToFrontInternal(taskId);
|
||||
endStabilizationSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskRemoved(int taskId) {
|
||||
onTaskRemovedInternal(taskId);
|
||||
endStabilizationSession();
|
||||
}
|
||||
};
|
||||
|
||||
// Task ids ordered based on recency, 0th index is the latest task
|
||||
private final IntArray mOrderedTaskIds;
|
||||
// Task ids ordered based on recency, 0th index is the least recent task
|
||||
private final IntArray mSystemOrder;
|
||||
private final IntArray mStabilizedOrder;
|
||||
|
||||
// Wrapper objects used for sorting tasks
|
||||
private final ArrayList<TaskWrapper> mTaskWrappers = new ArrayList<>();
|
||||
|
||||
// Information about recent task re-order which has not been applied yet
|
||||
private int mScheduledMoveTaskId = INVALID_TASK_ID;
|
||||
private long mScheduledMoveTime = 0;
|
||||
private boolean mInStabilizationSession;
|
||||
private long mSessionStartTime;
|
||||
|
||||
public TaskListStabilizer() {
|
||||
if (ENABLE_TASK_STABILIZER.get()) {
|
||||
// Initialize the task ids map
|
||||
List<RecentTaskInfo> rawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
|
||||
Integer.MAX_VALUE, Process.myUserHandle().getIdentifier());
|
||||
mOrderedTaskIds = new IntArray(rawTasks.size());
|
||||
for (RecentTaskInfo info : rawTasks) {
|
||||
mOrderedTaskIds.add(new TaskKey(info).id);
|
||||
}
|
||||
|
||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
|
||||
} else {
|
||||
mOrderedTaskIds = null;
|
||||
// Initialize the task ids map
|
||||
List<RecentTaskInfo> rawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
|
||||
Integer.MAX_VALUE, Process.myUserHandle().getIdentifier());
|
||||
mSystemOrder = new IntArray(rawTasks.size());
|
||||
for (RecentTaskInfo info : rawTasks) {
|
||||
mSystemOrder.add(new TaskKey(info).id);
|
||||
}
|
||||
// We will lazily copy the task id's from mSystemOrder when a stabilization session starts.
|
||||
mStabilizedOrder = new IntArray(rawTasks.size());
|
||||
|
||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
|
||||
}
|
||||
|
||||
private synchronized void onTaskCreatedInternal(int taskId) {
|
||||
applyScheduledMoveUnchecked();
|
||||
mOrderedTaskIds.add(taskId);
|
||||
}
|
||||
|
||||
private synchronized void onTaskRemovedInternal(int taskId) {
|
||||
applyScheduledMoveUnchecked();
|
||||
mOrderedTaskIds.removeValue(taskId);
|
||||
}
|
||||
|
||||
private void applyScheduledMoveUnchecked() {
|
||||
if (mScheduledMoveTaskId != INVALID_TASK_ID) {
|
||||
// Mode the scheduled task to front
|
||||
mOrderedTaskIds.removeValue(mScheduledMoveTaskId);
|
||||
mOrderedTaskIds.add(mScheduledMoveTaskId);
|
||||
mScheduledMoveTaskId = INVALID_TASK_ID;
|
||||
public synchronized void startStabilizationSession() {
|
||||
if (!mInStabilizationSession) {
|
||||
mStabilizedOrder.clear();
|
||||
mStabilizedOrder.addAll(mSystemOrder);
|
||||
}
|
||||
mInStabilizationSession = true;
|
||||
mSessionStartTime = SystemClock.uptimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the scheduled move has timed out and moves the task to front accordingly.
|
||||
*/
|
||||
private void applyScheduledMoveIfTime() {
|
||||
if (mScheduledMoveTaskId != INVALID_TASK_ID
|
||||
&& (SystemClock.uptimeMillis() - mScheduledMoveTime) > TASK_CACHE_TIMEOUT_MS) {
|
||||
applyScheduledMoveUnchecked();
|
||||
}
|
||||
public synchronized void endStabilizationSession() {
|
||||
mInStabilizationSession = false;
|
||||
}
|
||||
|
||||
private synchronized void onTaskMovedToFrontInternal(int taskId) {
|
||||
applyScheduledMoveIfTime();
|
||||
mScheduledMoveTaskId = taskId;
|
||||
mScheduledMoveTime = SystemClock.uptimeMillis();
|
||||
}
|
||||
|
||||
|
||||
public synchronized ArrayList<Task> reorder(ArrayList<Task> tasks) {
|
||||
if (!ENABLE_TASK_STABILIZER.get()) {
|
||||
return tasks;
|
||||
mSystemOrder.clear();
|
||||
for (Task task : tasks) {
|
||||
mSystemOrder.add(task.key.id);
|
||||
}
|
||||
|
||||
applyScheduledMoveIfTime();
|
||||
if ((SystemClock.uptimeMillis() - mSessionStartTime) > TASK_CACHE_TIMEOUT_MS) {
|
||||
endStabilizationSession();
|
||||
}
|
||||
|
||||
if (!mInStabilizationSession) {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
// Ensure that we have enough wrappers
|
||||
int taskCount = tasks.size();
|
||||
|
@ -139,7 +115,7 @@ public class TaskListStabilizer {
|
|||
for (int i = 0; i < taskCount; i++){
|
||||
TaskWrapper wrapper = listToSort.get(i);
|
||||
wrapper.task = tasks.get(i);
|
||||
wrapper.index = mOrderedTaskIds.indexOf(wrapper.task.key.id);
|
||||
wrapper.index = mStabilizedOrder.indexOf(wrapper.task.key.id);
|
||||
|
||||
// Ensure that missing tasks are put in the front, in the order they appear in the
|
||||
// original list
|
||||
|
|
|
@ -200,11 +200,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
|||
this.containerType = containerType;
|
||||
}
|
||||
|
||||
// 0 is app, 1 is overview
|
||||
/** 0 is app, 1 is overview */
|
||||
public final float endShift;
|
||||
/** The state to apply when we reach this final target */
|
||||
public final int endState;
|
||||
/** Whether the target is in the launcher activity */
|
||||
public final boolean isLauncher;
|
||||
/** Whether the user can start a new gesture while this one is finishing */
|
||||
public final boolean canBeContinued;
|
||||
/** Used to log where the user ended up after the gesture ends */
|
||||
public final int containerType;
|
||||
}
|
||||
|
||||
|
@ -926,6 +930,17 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
|
|||
private void animateToProgressInternal(float start, float end, long duration,
|
||||
Interpolator interpolator, GestureEndTarget target, float velocityPxPerMs) {
|
||||
mGestureEndTarget = target;
|
||||
|
||||
if (mGestureEndTarget.canBeContinued) {
|
||||
// Because we might continue this gesture, e.g. for consecutive quick switch, we need to
|
||||
// stabilize the task list so that tasks don't rearrange in the middle of the gesture.
|
||||
RecentsModel.INSTANCE.get(mContext).startStabilizationSession();
|
||||
} else if (mGestureEndTarget.isLauncher) {
|
||||
// Otherwise, if we're going to home or overview,
|
||||
// we reset the tasks to a consistent start state.
|
||||
RecentsModel.INSTANCE.get(mContext).endStabilizationSession();
|
||||
}
|
||||
|
||||
HomeAnimationFactory homeAnimFactory;
|
||||
Animator windowAnim;
|
||||
if (mGestureEndTarget == HOME) {
|
||||
|
|
|
@ -26,7 +26,6 @@ public class FlagOverrideSampleTest {
|
|||
@Test
|
||||
public void withFlagOn() {
|
||||
assertTrue(FeatureFlags.EXAMPLE_FLAG.get());
|
||||
assertFalse(FeatureFlags.QUICK_SWITCH.get());
|
||||
assertFalse(FeatureFlags.STYLE_WALLPAPER.get());
|
||||
}
|
||||
|
||||
|
|
|
@ -88,10 +88,6 @@ abstract class BaseFlags {
|
|||
// trying to make them fit the orientation the device is in.
|
||||
public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
|
||||
|
||||
public static final ToggleableGlobalSettingsFlag QUICK_SWITCH
|
||||
= new ToggleableGlobalSettingsFlag("QUICK_SWITCH", false,
|
||||
"Swiping right on the nav bar while in an app switches to the previous app");
|
||||
|
||||
public static final ToggleableGlobalSettingsFlag STYLE_WALLPAPER
|
||||
= new ToggleableGlobalSettingsFlag("STYLE_WALLPAPER", false,
|
||||
"Direct users to the new ThemePicker based WallpaperPicker");
|
||||
|
@ -102,10 +98,6 @@ abstract class BaseFlags {
|
|||
public static final TogglableFlag APPLY_CONFIG_AT_RUNTIME = new TogglableFlag(
|
||||
"APPLY_CONFIG_AT_RUNTIME", true, "Apply display changes dynamically");
|
||||
|
||||
public static final ToggleableGlobalSettingsFlag ENABLE_TASK_STABILIZER
|
||||
= new ToggleableGlobalSettingsFlag("ENABLE_TASK_STABILIZER", false,
|
||||
"Stable task list across fast task switches");
|
||||
|
||||
public static final TogglableFlag QUICKSTEP_SPRINGS = new TogglableFlag("QUICKSTEP_SPRINGS",
|
||||
false, "Enable springs for quickstep animations");
|
||||
|
||||
|
|
Loading…
Reference in New Issue