Merge "Abstracting out state handler logic into base classes so that it can also be used in different activity" into ub-launcher3-rvc-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index eb976c7..dd41d25 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -40,6 +40,7 @@
import android.view.MotionEvent;
import android.view.animation.Interpolator;
+import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -128,7 +129,6 @@
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
- protected int mLastStartedTaskId = -1;
private boolean mRecentsViewScrollLinked = false;
@@ -218,11 +218,16 @@
if (!mCanceled) {
TaskView nextTask = mRecentsView.getTaskView(taskId);
if (nextTask != null) {
- mLastStartedTaskId = taskId;
+ mGestureState.updateLastStartedTaskId(taskId);
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
success -> {
resultCallback.accept(success);
- if (!success) {
+ if (success) {
+ if (mRecentsView.indexOfChild(nextTask)
+ == getLastAppearedTaskIndex()) {
+ onRestartLastAppearedTask();
+ }
+ } else {
mActivityInterface.onLaunchTaskFailed();
nextTask.notifyTaskLaunchFailed(TAG);
mRecentsAnimationController.finish(true /* toRecents */, null);
@@ -236,6 +241,19 @@
}
/**
+ * Called when we successfully startNewTask() on the task that was previously running. Normally
+ * we call resumeLastTask() when returning to the previously running task, but this handles a
+ * specific edge case: if we switch from A to B, and back to A before B appears, we need to
+ * start A again to ensure it stays on top.
+ */
+ @CallSuper
+ protected void onRestartLastAppearedTask() {
+ // Finish the controller here, since we won't get onTaskAppeared() for a task that already
+ // appeared.
+ mRecentsAnimationController.finish(false, null);
+ }
+
+ /**
* Runs the given {@param action} if the recents animation has already started, or queues it to
* be run when it is next started.
*/
@@ -331,6 +349,14 @@
: mRecentsView.getRunningTaskIndex();
}
+ /**
+ * @return Whether we are continuing a gesture that already landed on a new task,
+ * but before that task appeared.
+ */
+ protected boolean hasStartedNewTask() {
+ return mGestureState.getLastStartedTaskId() != -1;
+ }
+
protected void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
index 21c8c20..e1f34ed 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -725,7 +725,8 @@
if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
return false;
}
- if (appearedTaskTarget.taskId == mLastStartedTaskId) {
+ if (mGestureState.getEndTarget() == NEW_TASK
+ && appearedTaskTarget.taskId == mGestureState.getLastStartedTaskId()) {
reset();
return true;
}
@@ -1016,17 +1017,19 @@
if (mRecentsView != null) {
int taskToLaunch = mRecentsView.getNextPage();
int runningTask = getLastAppearedTaskIndex();
- if (target == NEW_TASK && taskToLaunch == runningTask) {
+ boolean hasStartedNewTask = hasStartedNewTask();
+ if (target == NEW_TASK && taskToLaunch == runningTask
+ && !hasStartedNewTask) {
// We are about to launch the current running task, so use LAST_TASK
// state instead of NEW_TASK. This could happen, for example, if our
// scroll is aborted after we determined the target to be NEW_TASK.
mGestureState.setEndTarget(LAST_TASK);
- } else if (target == LAST_TASK && taskToLaunch != runningTask) {
+ } else if (target == LAST_TASK && hasStartedNewTask) {
// We are about to re-launch the previously running task, but we can't
// just finish the controller like we normally would because that would
- // instead resume the last task that appeared. As a workaround, launch
- // the task as if it were a new task.
- // TODO: is this expected?
+ // instead resume the last task that appeared, and not ensure that this
+ // task is restored to the top. To address this, re-launch the task as
+ // if it were a new task.
mGestureState.setEndTarget(NEW_TASK);
}
}
@@ -1164,6 +1167,12 @@
});
}
+ @Override
+ protected void onRestartLastAppearedTask() {
+ super.onRestartLastAppearedTask();
+ reset();
+ }
+
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index c44d9d7..4b2fc75 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -518,6 +518,7 @@
ActiveGestureLog.INSTANCE.generateAndSetLogId());
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
gestureState.updateRunningTask(mGestureState.getRunningTask());
+ gestureState.updateLastStartedTaskId(mGestureState.getLastStartedTaskId());
} else {
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
() -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index f06e1a6..9b515ae 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep;
-import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import android.app.ActivityManager;
@@ -121,6 +120,7 @@
private ActivityManager.RunningTaskInfo mRunningTask;
private GestureEndTarget mEndTarget;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
+ private int mLastStartedTaskId = -1;
public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
mHomeIntent = componentObserver.getHomeIntent();
@@ -139,6 +139,7 @@
mRunningTask = other.mRunningTask;
mEndTarget = other.mEndTarget;
mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
+ mLastStartedTaskId = other.mLastStartedTaskId;
}
public GestureState() {
@@ -235,6 +236,21 @@
}
/**
+ * Updates the last task that we started via startActivityFromRecents() during this gesture.
+ */
+ public void updateLastStartedTaskId(int lastStartedTaskId) {
+ mLastStartedTaskId = lastStartedTaskId;
+ }
+
+ /**
+ * @return The id of the task that was most recently started during this gesture, or -1 if
+ * no task has been started yet (i.e. we haven't settled on a new task).
+ */
+ public int getLastStartedTaskId() {
+ return mLastStartedTaskId;
+ }
+
+ /**
* @return the end target for this gesture (if known).
*/
public GestureEndTarget getEndTarget() {
@@ -300,6 +316,7 @@
pw.println(" runningTask=" + mRunningTask);
pw.println(" endTarget=" + mEndTarget);
pw.println(" lastAppearedTaskTarget=" + mLastAppearedTaskTarget);
+ pw.println(" lastStartedTaskId=" + mLastStartedTaskId);
pw.println(" isRecentsAnimationRunning=" + isRecentsAnimationRunning());
}
}
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5f4bd8e..2efa66f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -103,9 +103,9 @@
<!-- Label for install drop target. [CHAR_LIMIT=20] -->
<string name="install_drop_target_label">Install</string>
<!-- Label for install dismiss prediction. -->
- <string translatable="false" name="dismiss_prediction_label">Don\'t suggest app</string>
+ <string name="dismiss_prediction_label">Don\'t suggest app</string>
<!-- Label for pinning predicted app. -->
- <string name="pin_prediction" translatable="false">Pin Prediction</string>
+ <string name="pin_prediction">Pin Prediction</string>
<!-- Permissions: -->
@@ -342,7 +342,7 @@
<!--- heading shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_title">Work profile is paused</string>
<!--- body shown when user opens work apps tab while work apps are paused -->
- <string name="work_apps_paused_body">Work apps can\’t send you notifications, use your battery, or access your location</string>
+ <string name="work_apps_paused_body">Work apps can\'t send you notifications, use your battery, or access your location</string>
<!-- content description for paused work apps list -->
<string name="work_apps_paused_content_description">Work profile is paused. Work apps can\’t send you notifications, use your battery, or access your location</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index a2c0f23..ce31dab 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -90,7 +90,7 @@
<item name="android:textColorHint">#A0FFFFFF</item>
<item name="android:colorControlHighlight">#A0FFFFFF</item>
<item name="android:colorPrimary">#FF212121</item>
- <item name="allAppsScrimColor">#FF212121</item>
+ <item name="allAppsScrimColor">#FF000000</item>
<item name="allAppsInterimScrimAlpha">102</item>
<item name="allAppsNavBarScrimColor">#80000000</item>
<item name="popupColorPrimary">#3C4043</item> <!-- Gray 800 -->
@@ -229,9 +229,7 @@
<style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
<style name="PrimaryMediumText" parent="@android:style/TextAppearance.DeviceDefault.Medium"/>
- <style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
- <item name="android:textStyle">bold</item>
- </style>
+ <style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
<style name="TextTitle" parent="@android:style/TextAppearance.DeviceDefault" />
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 90aaf44..9e6282e 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -851,20 +851,23 @@
}
private List<AppInfo> loadCachedPredictions() {
- List<ComponentKey> componentKeys = mApp.getPredictionModel().getPredictionComponentKeys();
- List<AppInfo> results = new ArrayList<>();
- if (componentKeys == null) return results;
- List<LauncherActivityInfo> l;
- mBgDataModel.cachedPredictedItems.clear();
- for (ComponentKey key : componentKeys) {
- l = mLauncherApps.getActivityList(key.componentName.getPackageName(), key.user);
- if (l.size() == 0) continue;
- boolean quietMode = mUserManager.isQuietModeEnabled(key.user);
- AppInfo info = new AppInfo(l.get(0), key.user, quietMode);
- mBgDataModel.cachedPredictedItems.add(info);
- mIconCache.getTitleAndIcon(info, false);
+ synchronized (mBgDataModel) {
+ List<ComponentKey> componentKeys =
+ mApp.getPredictionModel().getPredictionComponentKeys();
+ List<AppInfo> results = new ArrayList<>();
+ if (componentKeys == null) return results;
+ List<LauncherActivityInfo> l;
+ mBgDataModel.cachedPredictedItems.clear();
+ for (ComponentKey key : componentKeys) {
+ l = mLauncherApps.getActivityList(key.componentName.getPackageName(), key.user);
+ if (l.size() == 0) continue;
+ boolean quietMode = mUserManager.isQuietModeEnabled(key.user);
+ AppInfo info = new AppInfo(l.get(0), key.user, quietMode);
+ mBgDataModel.cachedPredictedItems.add(info);
+ mIconCache.getTitleAndIcon(info, false);
+ }
+ return results;
}
- return results;
}
private List<LauncherActivityInfo> loadAllApps() {
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index 97d72ed..875eefb 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -105,6 +105,11 @@
super(config, isRtl);
mListener = l;
mDir = dir;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "SingleAxisSwipeDetector.ctor "
+ + l.getClass().getSimpleName()
+ + " @ " + android.util.Log.getStackTraceString(new Throwable()));
+ }
}
public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index e7da0621..7cce044 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -37,6 +37,8 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -276,6 +278,15 @@
mTargetContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
mLauncherPid = mLauncher.getPid();
+
+ UserManager userManager = mTargetContext.getSystemService(UserManager.class);
+ if (userManager != null) {
+ for (UserHandle userHandle : userManager.getUserProfiles()) {
+ if (!userHandle.isSystem()) {
+ mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier());
+ }
+ }
+ }
}
@After