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:
Tony 2019-02-15 23:39:04 -08:00
parent 5616670a5a
commit 60ac5d2b34
6 changed files with 76 additions and 76 deletions

View File

@ -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.
*

View File

@ -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.
*

View File

@ -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

View File

@ -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) {

View File

@ -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());
}

View File

@ -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");