Merge "Loading widget description on the background thread" into udc-dev
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index ed78e2d..75cfd05 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -207,6 +207,10 @@
com.android.launcher3.taskbar.Utilities.setOverviewDragState(
mControllers, finalState.disallowTaskbarGlobalDrag(),
disallowLongClick, finalState.allowTaskbarInitialSplitSelection());
+ // LauncherTaskbarUIController depends on the state when checking whether
+ // to handle resume, so it should also be poked if current state changes
+ mLauncher.getTaskbarUIController().onLauncherResumedOrPaused(
+ mLauncher.hasBeenResumed());
}
};
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 5333cbe..7d47945 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -2114,12 +2114,11 @@
}
protected void linkRecentsViewScroll() {
- SurfaceTransactionApplier.create(mRecentsView, applier -> {
- runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
- .setSyncTransactionApplier(applier));
- runOnRecentsAnimationAndLauncherBound(() ->
- mRecentsAnimationTargets.addReleaseCheck(applier));
- });
+ SurfaceTransactionApplier applier = new SurfaceTransactionApplier(mRecentsView);
+ runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
+ .setSyncTransactionApplier(applier));
+ runOnRecentsAnimationAndLauncherBound(() ->
+ mRecentsAnimationTargets.addReleaseCheck(applier));
mRecentsView.addOnScrollChangedListener(mOnRecentsScrollListener);
runOnRecentsAnimationAndLauncherBound(() ->
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 913f08f..d798e62 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -145,6 +145,9 @@
* @param filter Returns true if GroupTask should be in the list of considerations
*/
public void isTaskRemoved(int taskId, Consumer<Boolean> callback, Predicate<GroupTask> filter) {
+ // Invalidate the existing list before checking to ensure this reflects the current state in
+ // the system
+ mTaskList.onRecentTasksChanged();
mTaskList.getTasks(true /* loadKeysOnly */, (taskGroups) -> {
for (GroupTask group : taskGroups) {
if (group.containsTask(taskId)) {
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 4b1dd43..074aedd 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -79,7 +79,7 @@
}
@Override
- public void startHome() {
+ public void startHome(boolean animated) {
mActivity.startHome();
AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
}
diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
index 95473dc..bb028a7 100644
--- a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
+++ b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
@@ -22,13 +22,11 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
import android.view.ViewRootImpl;
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
-import java.util.function.Consumer;
-
-
/**
* Helper class to apply surface transactions in sync with RenderThread similar to
* android.view.SyncRtSurfaceTransactionApplier
@@ -39,22 +37,47 @@
private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
- private final SurfaceControl mBarrierSurfaceControl;
- private final ViewRootImpl mTargetViewRootImpl;
private final Handler mApplyHandler;
+ private boolean mInitialized;
+ private SurfaceControl mBarrierSurfaceControl;
+ private ViewRootImpl mTargetViewRootImpl;
+
private int mLastSequenceNumber = 0;
/**
* @param targetView The view in the surface that acts as synchronization anchor.
*/
public SurfaceTransactionApplier(View targetView) {
- mTargetViewRootImpl = targetView.getViewRootImpl();
- mBarrierSurfaceControl = mTargetViewRootImpl.getSurfaceControl();
+ if (targetView.isAttachedToWindow()) {
+ initialize(targetView);
+ } else {
+ mInitialized = false;
+ targetView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ if (!mInitialized) {
+ targetView.removeOnAttachStateChangeListener(this);
+ initialize(targetView);
+ }
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ // Do nothing
+ }
+ });
+ }
mApplyHandler = new Handler(this::onApplyMessage);
setCanRelease(true);
}
+ private void initialize(View view) {
+ mTargetViewRootImpl = view.getViewRootImpl();
+ mBarrierSurfaceControl = mTargetViewRootImpl.getSurfaceControl();
+ mInitialized = true;
+ }
+
protected boolean onApplyMessage(Message msg) {
if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) {
setCanRelease(msg.arg1 == mLastSequenceNumber);
@@ -70,6 +93,10 @@
* this method to avoid synchronization issues.
*/
public void scheduleApply(SurfaceTransaction params) {
+ if (!mInitialized) {
+ params.getTransaction().apply();
+ return;
+ }
View view = mTargetViewRootImpl.getView();
if (view == null) {
return;
@@ -93,33 +120,4 @@
// Make sure a frame gets scheduled.
view.invalidate();
}
-
- /**
- * Creates an instance of SurfaceTransactionApplier, deferring until the target view is
- * attached if necessary.
- */
- public static void create(
- final View targetView, final Consumer<SurfaceTransactionApplier> callback) {
- if (targetView == null) {
- // No target view, no applier
- callback.accept(null);
- } else if (targetView.isAttachedToWindow()) {
- // Already attached, we're good to go
- callback.accept(new SurfaceTransactionApplier(targetView));
- } else {
- // Haven't been attached before we can get the view root
- targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- targetView.removeOnAttachStateChangeListener(this);
- callback.accept(new SurfaceTransactionApplier(targetView));
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- // Do nothing
- }
- });
- }
- }
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
new file mode 100644
index 0000000..c22e0bc
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
+import android.app.Activity;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
+import com.android.quickstep.RecentsModel;
+
+/**
+ * This class tracks the failure of a task launch through the TaskView.launchTask() call, in an
+ * edge case in which starting a new task may initially succeed (startActivity returns true), but
+ * the launch ultimately fails if the activity finishes while it is resuming.
+ *
+ * There are two signals this class checks, the launcher lifecycle and the transition completion.
+ * If we hit either of those signals and the task is no longer valid, then the registered failure
+ * callback will be notified.
+ */
+public class TaskRemovedDuringLaunchListener implements ActivityLifecycleCallbacksAdapter {
+
+ private Activity mActivity;
+ private int mLaunchedTaskId = INVALID_TASK_ID;
+ private Runnable mTaskLaunchFailedCallback = null;
+
+ /**
+ * Registers a failure listener callback if it detects a scenario in which an app launch
+ * failed before the transition finished.
+ */
+ public void register(Activity activity, int launchedTaskId,
+ @NonNull Runnable taskLaunchFailedCallback) {
+ activity.registerActivityLifecycleCallbacks(this);
+ mActivity = activity;
+ mLaunchedTaskId = launchedTaskId;
+ mTaskLaunchFailedCallback = taskLaunchFailedCallback;
+ }
+
+ /**
+ * Unregisters the failure listener.
+ */
+ private void unregister() {
+ mActivity.unregisterActivityLifecycleCallbacks(this);
+ mActivity = null;
+ mLaunchedTaskId = INVALID_TASK_ID;
+ mTaskLaunchFailedCallback = null;
+ }
+
+ /**
+ * Called when the transition finishes.
+ */
+ public void onTransitionFinished() {
+ // The transition finished and Launcher was not stopped, check if the launch failed
+ checkTaskLaunchFailed();
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ // The normal task launch case, Launcher stops and updates its state correctly
+ unregister();
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ // The transition hasn't finished but Launcher was resumed, check if the launch failed
+ checkTaskLaunchFailed();
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ // If we somehow don't get any of the above signals, then just unregister this listener
+ unregister();
+ }
+
+ private void checkTaskLaunchFailed() {
+ if (mLaunchedTaskId != INVALID_TASK_ID) {
+ final int launchedTaskId = mLaunchedTaskId;
+ final Runnable taskLaunchFailedCallback = mTaskLaunchFailedCallback;
+ RecentsModel.INSTANCE.getNoCreate().isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
+ if (taskRemoved) {
+ ActiveGestureLog.INSTANCE.addLog("Launch failed, task (id=" + launchedTaskId
+ + ") finished mid transition");
+ taskLaunchFailedCallback.run();
+ }
+ }, (task) -> true /* filter */);
+ unregister();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 379722b..1cfaf14 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -321,7 +321,7 @@
}
@Override
- public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
+ public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
launchTasks();
callback.accept(true);
}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 5bfd035..c6c84bd 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -237,9 +237,9 @@
}
@Override
- public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
+ public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
getRecentsView().getSplitSelectController().launchTasks(mTask.key.id, mSecondaryTask.key.id,
- SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList,
+ SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT, callback, isQuickswitch,
getSplitRatio());
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 8ff0e9b..2008129 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -39,6 +39,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.PendingSplitSelectInfo;
@@ -79,9 +80,11 @@
}
@Override
- public void startHome() {
- mActivity.getStateManager().goToState(NORMAL);
- AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
+ public void startHome(boolean animated) {
+ StateManager stateManager = mActivity.getStateManager();
+ animated &= stateManager.shouldAnimateStateChange();
+ stateManager.goToState(NORMAL, animated);
+ AbstractFloatingView.closeAllOpenViews(mActivity, animated);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index f0afa69..ff5af28 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2285,7 +2285,11 @@
}
}
- public abstract void startHome();
+ public void startHome() {
+ startHome(mActivity.isStarted());
+ }
+
+ public abstract void startHome(boolean animated);
public void reset() {
setCurrentTask(-1);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 53660b5..796cd62 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -102,6 +102,7 @@
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.TaskCornerRadius;
+import com.android.quickstep.util.TaskRemovedDuringLaunchListener;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -815,23 +816,44 @@
* Starts the task associated with this view without any animation
*/
public void launchTask(@NonNull Consumer<Boolean> callback) {
- launchTask(callback, false /* freezeTaskList */);
+ launchTask(callback, false /* isQuickswitch */);
}
/**
* Starts the task associated with this view without any animation
*/
- public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
+ public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
if (mTask != null) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
+ final TaskRemovedDuringLaunchListener
+ failureListener = new TaskRemovedDuringLaunchListener();
+ if (isQuickswitch) {
+ // We only listen for failures to launch in quickswitch because the during this
+ // gesture launcher is in the background state, vs other launches which are in
+ // the actual overview state
+ failureListener.register(mActivity, mTask.key.id, () -> {
+ notifyTaskLaunchFailed(TAG);
+ // Disable animations for now, as it is an edge case and the app usually covers
+ // launcher and also any state transition animation also gets clobbered by
+ // QuickstepTransitionManager.createWallpaperOpenAnimations when launcher
+ // shows again
+ getRecentsView().startHome(false /* animated */);
+ });
+ }
// Indicate success once the system has indicated that the transition has started
- ActivityOptions opts = makeCustomAnimation(getContext(), 0, 0,
- () -> callback.accept(true), MAIN_EXECUTOR.getHandler());
+ ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(getContext(), 0, 0,
+ MAIN_EXECUTOR.getHandler(),
+ elapsedRealTime -> {
+ callback.accept(true);
+ },
+ elapsedRealTime -> {
+ failureListener.onTransitionFinished();
+ });
opts.setLaunchDisplayId(
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
- if (freezeTaskList) {
+ if (isQuickswitch) {
opts.setFreezeRecentTasksReordering();
}
opts.setDisableStartingWindow(mSnapshotView.shouldShowSplashView());
diff --git a/src/com/android/launcher3/DropTargetHandler.kt b/src/com/android/launcher3/DropTargetHandler.kt
index 277f8b3..6560e16 100644
--- a/src/com/android/launcher3/DropTargetHandler.kt
+++ b/src/com/android/launcher3/DropTargetHandler.kt
@@ -6,7 +6,6 @@
import com.android.launcher3.SecondaryDropTarget.DeferredOnComplete
import com.android.launcher3.dragndrop.DragLayer
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
-import com.android.launcher3.model.ModelWriter
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo
import com.android.launcher3.util.IntSet
@@ -22,8 +21,6 @@
class DropTargetHandler(launcher: Launcher) {
val mLauncher: Launcher = launcher
- val modelWriter: ModelWriter = mLauncher.modelWriter
-
fun onDropAnimationComplete() {
mLauncher.stateManager.goToState(LauncherState.NORMAL)
}
@@ -87,7 +84,7 @@
else mLauncher.workspace.currentPageScreenIds
val onUndoClicked = Runnable {
mLauncher.setPagesToBindSynchronously(pageIds)
- modelWriter.abortDelete()
+ mLauncher.modelWriter.abortDelete()
mLauncher.statsLogManager.logger().log(LauncherEvent.LAUNCHER_UNDO)
}
@@ -95,7 +92,7 @@
mLauncher,
R.string.item_removed,
R.string.undo,
- modelWriter::commitDelete,
+ mLauncher.modelWriter::commitDelete,
onUndoClicked
)
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4764d72..29b0f08 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1621,6 +1621,9 @@
return mModel;
}
+ /**
+ * Returns the ModelWriter writer, make sure to call the function every time you want to use it.
+ */
public ModelWriter getModelWriter() {
return mModelWriter;
}
diff --git a/src/com/android/launcher3/logging/StartupLatencyLogger.kt b/src/com/android/launcher3/logging/StartupLatencyLogger.kt
index 27b8c3b..93e9de5 100644
--- a/src/com/android/launcher3/logging/StartupLatencyLogger.kt
+++ b/src/com/android/launcher3/logging/StartupLatencyLogger.kt
@@ -21,14 +21,13 @@
const val UNSET_LONG = -1L
}
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
val startTimeByEvent = SparseLongArray()
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
val endTimeByEvent = SparseLongArray()
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- var cardinality: Int = UNSET_INT
- @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) var cardinality: Int = UNSET_INT
+ @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
var workspaceLoadStartTime: Long = UNSET_LONG
private var isInTest = false