Merge "Maintain if any task has been dismissed in RecentsView state" into main
diff --git a/Android.bp b/Android.bp
index 962f269..e358005 100644
--- a/Android.bp
+++ b/Android.bp
@@ -19,6 +19,17 @@
 
 min_launcher3_sdk_version = "30"
 
+// Targets that don't inherit framework aconfig libs (i.e., those that don't set
+// `platform_apis: true`) must manually link them.
+java_defaults {
+    name: "launcher-non-platform-apis-defaults",
+    static_libs: [
+        "android.os.flags-aconfig-java",
+        "android.appwidget.flags-aconfig-java",
+        "com.android.window.flags.window-aconfig-java",
+    ]
+}
+
 // Common source files used to build launcher (java and kotlin)
 // All sources are split so they can be reused in many other libraries/apps in other folders
 
@@ -141,7 +152,6 @@
     static_libs: [
         "LauncherPluginLib",
         "launcher_quickstep_log_protos_lite",
-        "android.os.flags-aconfig-java",
         "androidx-constraintlayout_constraintlayout",
         "androidx.recyclerview_recyclerview",
         "androidx.dynamicanimation_dynamicanimation",
@@ -163,8 +173,6 @@
         "kotlinx_coroutines",
         "com_android_launcher3_flags_lib",
         "com_android_wm_shell_flags_lib",
-        "android.appwidget.flags-aconfig-java",
-        "com.android.window.flags.window-aconfig-java",
     ],
     manifest: "AndroidManifest-common.xml",
     sdk_version: "current",
@@ -179,6 +187,7 @@
 //
 android_app {
     name: "Launcher3",
+    defaults: ["launcher-non-platform-apis-defaults"],
 
     static_libs: [
         "Launcher3ResLib",
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 6d54abd..78c6d4b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -456,7 +456,12 @@
      * Show Taskbar upon receiving broadcast
      */
     public void showTaskbarFromBroadcast() {
-        mControllers.taskbarStashController.showTaskbarFromBroadcast();
+        // If user is in middle of taskbar education handle go to next step of education
+        if (mControllers.taskbarEduTooltipController.isBeforeTooltipFeaturesStep()) {
+            mControllers.taskbarEduTooltipController.hide();
+            mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
+        }
+        mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
     }
 
     /** Toggles Taskbar All Apps overlay. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 64fb04b..267e19c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -286,18 +286,6 @@
     }
 
     /**
-     * Show Taskbar upon receiving broadcast
-     */
-    public void showTaskbarFromBroadcast() {
-        // If user is in middle of taskbar education handle go to next step of education
-        if (mControllers.taskbarEduTooltipController.isBeforeTooltipFeaturesStep()) {
-            mControllers.taskbarEduTooltipController.hide();
-            mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
-        }
-        updateAndAnimateTransientTaskbar(false);
-    }
-
-    /**
      * Initializes the controller
      */
     public void init(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index ad81509..0f9de16 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -400,7 +400,7 @@
         addedBubble.getView().setOnClickListener(mBubbleClickListener);
         mBubbleDragController.setupBubbleView(addedBubble.getView());
         if (!suppressAnimation) {
-            animateBubbleNotification(addedBubble, isExpanding, /* isUpdate= */ true);
+            animateBubbleNotification(addedBubble, isExpanding, /* isUpdate= */ false);
         }
     }
 
@@ -428,7 +428,7 @@
                 }
                 return;
             }
-            animateBubbleNotification(bubble, isExpanding, /* isUpdate= */ true);
+            animateBubbleNotification(bubble, isExpanding, /* isUpdate= */ false);
         } else {
             Log.w(TAG, "addBubble, bubble was null!");
         }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 0368f3a..3a39cf2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -110,6 +110,7 @@
             // taskbar icons disappearing before hotseat icons show up.
             float scrimUpperBoundFromSplit =
                     QuickstepTransitionManager.getTaskbarToHomeDuration() / (float) config.duration;
+            scrimUpperBoundFromSplit = Math.min(scrimUpperBoundFromSplit, 1f);
             config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, 0, 0.25f));
             config.setInterpolator(ANIM_SCRIM_FADE,
                     fromState == OVERVIEW_SPLIT_SELECT
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index f902284..cd62265 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -33,7 +33,6 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
@@ -417,8 +416,7 @@
                         | SYSUI_STATE_QUICK_SETTINGS_EXPANDED
                         | SYSUI_STATE_MAGNIFICATION_OVERLAP
                         | SYSUI_STATE_DEVICE_DREAMING
-                        | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION
-                        | SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING;
+                        | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
         return (gestureDisablingStates & mSystemUiStateFlags) == 0 && homeOrOverviewEnabled;
     }
 
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 0d450c6..13b6447 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -70,6 +70,9 @@
  */
 public class OtherActivityInputConsumer extends ContextWrapper implements InputConsumer {
 
+    private static final String TAG = "OtherActivityInputConsumer";
+    private static final boolean DEBUG = true;
+
     public static final String DOWN_EVT = "OtherActivityInputConsumer.DOWN";
     private static final String UP_EVT = "OtherActivityInputConsumer.UP";
 
@@ -230,6 +233,9 @@
 
                 // Start the window animation on down to give more time for launcher to draw if the
                 // user didn't start the gesture over the back button
+                if (DEBUG) {
+                    Log.d(TAG, "ACTION_DOWN: mIsDeferredDownTarget=" + mIsDeferredDownTarget);
+                }
                 if (!mIsDeferredDownTarget) {
                     startTouchTrackingForWindowAnimation(ev.getEventTime());
                 }
@@ -284,9 +290,18 @@
 
                 float horizontalDist = Math.abs(displacementX);
                 float upDist = -displacement;
-                boolean passedSlop = mGestureState.isTrackpadGesture()
-                        || (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop
-                            && !mGestureState.isInExtendedSlopRegion());
+                boolean isTrackpadGesture = mGestureState.isTrackpadGesture();
+                float squaredHypot = squaredHypot(displacementX, displacementY);
+                boolean isInExtendedSlopRegion = !mGestureState.isInExtendedSlopRegion();
+                boolean passedSlop = isTrackpadGesture
+                        || (squaredHypot >= mSquaredTouchSlop
+                        && isInExtendedSlopRegion);
+                if (DEBUG) {
+                    Log.d(TAG, "ACTION_MOVE: passedSlop=" + passedSlop
+                            + " ( " + isTrackpadGesture
+                            + " || (" + squaredHypot + " >= " + mSquaredTouchSlop
+                            + " && " + isInExtendedSlopRegion + " ))");
+                }
 
                 if (!mPassedSlopOnThisGesture && passedSlop) {
                     mPassedSlopOnThisGesture = true;
@@ -306,6 +321,9 @@
                 boolean isLikelyToStartNewTask =
                         haveNotPassedSlopOnContinuedGesture || swipeWithinQuickSwitchRange;
 
+                if (DEBUG) {
+                    Log.d(TAG, "ACTION_MOVE: mPassedPilferInputSlop=" + mPassedPilferInputSlop);
+                }
                 if (!mPassedPilferInputSlop) {
                     if (passedSlop) {
                         // Horizontal gesture is not allowed in this region
@@ -394,6 +412,10 @@
         mInteractionHandler.initWhenReady(
                 "OtherActivityInputConsumer.startTouchTrackingForWindowAnimation");
 
+        if (DEBUG) {
+            Log.d(TAG, "startTouchTrackingForWindowAnimation: isRecentsAnimationRunning="
+                    + mTaskAnimationManager.isRecentsAnimationRunning());
+        }
         if (mTaskAnimationManager.isRecentsAnimationRunning()) {
             mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState);
             mActiveCallbacks.removeListener(mCleanupHandler);
@@ -422,6 +444,11 @@
      */
     private void finishTouchTracking(MotionEvent ev) {
         TraceHelper.INSTANCE.beginSection(UP_EVT);
+        if (DEBUG) {
+            Log.d(TAG, "finishTouchTracking: mPassedWindowMoveSlop=" + mPassedWindowMoveSlop);
+            Log.d(TAG, "finishTouchTracking: mInteractionHandler=" + mInteractionHandler);
+            Log.d(TAG, "finishTouchTracking: ev=" + ev);
+        }
 
         boolean isCanceled = ev.getActionMasked() == ACTION_CANCEL;
         if (mPassedWindowMoveSlop && mInteractionHandler != null) {
@@ -444,7 +471,14 @@
             // Since we start touch tracking on DOWN, we may reach this state without actually
             // starting the gesture. In that case, we need to clean-up an unfinished or un-started
             // animation.
+            if (DEBUG) {
+                Log.d(TAG, "finishTouchTracking: mActiveCallbacks=" + mActiveCallbacks);
+            }
             if (mActiveCallbacks != null && mInteractionHandler != null) {
+                if (DEBUG) {
+                    Log.d(TAG, "finishTouchTracking: isRecentsAnimationRunning="
+                            + mTaskAnimationManager.isRecentsAnimationRunning());
+                }
                 if (mTaskAnimationManager.isRecentsAnimationRunning()) {
                     // The animation started, but with no movement, in this case, there will be no
                     // animateToProgress so we have to manually finish here. In the case of
@@ -535,7 +569,13 @@
 
         public void onRecentsAnimationStart(RecentsAnimationController controller,
                 RecentsAnimationTargets targets) {
+            if (DEBUG) {
+                Log.d(TAG, "FinishImmediatelyHandler: queuing callback");
+            }
             Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
+                if (DEBUG) {
+                    Log.d(TAG, "FinishImmediatelyHandler: running callback");
+                }
                 controller.finish(false /* toRecents */, null);
             });
         }
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 48ed67b..56e91ed 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -139,6 +139,10 @@
 
         final float aspectRatio = destinationBounds.width() / (float) destinationBounds.height();
         String reasonForCreateOverlay = null; // For debugging purpose.
+
+        // Slightly larger app bounds to allow for off by 1 pixel source-rect-hint errors.
+        Rect overflowAppBounds = new Rect(appBounds.left - 1, appBounds.top - 1,
+                        appBounds.right + 1, appBounds.bottom + 1);
         if (sourceRectHint.isEmpty()) {
             reasonForCreateOverlay = "Source rect hint is empty";
         } else if (sourceRectHint.width() < destinationBounds.width()
@@ -149,7 +153,7 @@
             // animation in this case.
             reasonForCreateOverlay = "Source rect hint is too small " + sourceRectHint;
             sourceRectHint.setEmpty();
-        } else if (!appBounds.contains(sourceRectHint)) {
+        } else if (!overflowAppBounds.contains(sourceRectHint)) {
             // This is a situation in which the source hint rect is outside the app bounds, so it is
             // not a valid rectangle to use for cropping app surface
             reasonForCreateOverlay = "Source rect hint exceeds display bounds " + sourceRectHint;
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRule.kt
new file mode 100644
index 0000000..60c8dec
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRule.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 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.launcher3.taskbar.rules
+
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.ConstantItem
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING_IN_DESKTOP_MODE
+import kotlin.reflect.KProperty
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Rule that allows modifying the Taskbar pinned preferences.
+ *
+ * The original preference values are restored on teardown.
+ *
+ * If this rule is being used with [TaskbarUnitTestRule], make sure this rule is applied first.
+ *
+ * This rule is overkill if a test does not need to change the mode during Taskbar's lifecycle. If
+ * the mode is static, use [TaskbarModeRule] instead, which forces the mode. A test can class can
+ * declare both this rule and [TaskbarModeRule] but using both for a test method is unsupported.
+ */
+class TaskbarPinningPreferenceRule(context: TaskbarWindowSandboxContext) : TestRule {
+
+    private val prefs = LauncherPrefs.get(context)
+
+    var isPinned by PinningPreference(TASKBAR_PINNING)
+    var isPinnedInDesktopMode by PinningPreference(TASKBAR_PINNING_IN_DESKTOP_MODE)
+
+    override fun apply(base: Statement, description: Description): Statement {
+        return object : Statement() {
+            override fun evaluate() {
+                val wasPinned = isPinned
+                val wasPinnedInDesktopMode = isPinnedInDesktopMode
+                try {
+                    base.evaluate()
+                } finally {
+                    isPinned = wasPinned
+                    isPinnedInDesktopMode = wasPinnedInDesktopMode
+                }
+            }
+        }
+    }
+
+    private inner class PinningPreference(private val constantItem: ConstantItem<Boolean>) {
+        operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
+            return prefs.get(constantItem)
+        }
+
+        operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
+            getInstrumentation().runOnMainSync { prefs.put(constantItem, value) }
+        }
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
new file mode 100644
index 0000000..3f0a238
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarPinningPreferenceRuleTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 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.launcher3.taskbar.rules
+
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.util.DisplayController
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.Description
+import org.junit.runner.RunWith
+import org.junit.runners.model.Statement
+
+@RunWith(LauncherMultivalentJUnit::class)
+class TaskbarPinningPreferenceRuleTest {
+    private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+    private val preferenceRule = TaskbarPinningPreferenceRule(context)
+
+    @Test
+    fun testEnablePinning_verifyDisplayController() {
+        onSetup {
+            preferenceRule.isPinned = true
+            preferenceRule.isPinnedInDesktopMode = false
+            assertThat(DisplayController.isPinnedTaskbar(context)).isTrue()
+        }
+    }
+
+    @Test
+    fun testDisablePinning_verifyDisplayController() {
+        onSetup {
+            preferenceRule.isPinned = false
+            preferenceRule.isPinnedInDesktopMode = false
+            assertThat(DisplayController.isPinnedTaskbar(context)).isFalse()
+        }
+    }
+
+    @Test
+    fun testEnableDesktopPinning_verifyDisplayController() {
+        onSetup {
+            preferenceRule.isPinned = false
+            preferenceRule.isPinnedInDesktopMode = true
+            assertThat(DisplayController.isPinnedTaskbar(context)).isTrue()
+        }
+    }
+
+    @Test
+    fun testDisableDesktopPinning_verifyDisplayController() {
+        onSetup {
+            preferenceRule.isPinned = false
+            preferenceRule.isPinnedInDesktopMode = false
+            assertThat(DisplayController.isPinnedTaskbar(context)).isFalse()
+        }
+    }
+
+    @Test
+    fun testTearDown_afterTogglingPinnedPreference_preferenceReset() {
+        val wasPinned = preferenceRule.isPinned
+        onSetup { preferenceRule.isPinned = !preferenceRule.isPinned }
+        assertThat(preferenceRule.isPinned).isEqualTo(wasPinned)
+    }
+
+    @Test
+    fun testTearDown_afterTogglingDesktopPreference_preferenceReset() {
+        val wasPinnedInDesktopMode = preferenceRule.isPinnedInDesktopMode
+        onSetup { preferenceRule.isPinnedInDesktopMode = !preferenceRule.isPinnedInDesktopMode }
+        assertThat(preferenceRule.isPinnedInDesktopMode).isEqualTo(wasPinnedInDesktopMode)
+    }
+
+    /** Executes [runTest] after the [preferenceRule] setup phase completes. */
+    private fun onSetup(runTest: () -> Unit) {
+        preferenceRule.apply(
+            object : Statement() {
+                override fun evaluate() = runTest()
+            },
+            DESCRIPTION,
+        )
+    }
+
+    private companion object {
+        private val DESCRIPTION =
+            Description.createSuiteDescription(TaskbarPinningPreferenceRule::class.java)
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
index 8a64949..a966d2a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt
@@ -136,13 +136,19 @@
 
                 taskbarManager =
                     TestUtil.getOnUiThread {
-                        TaskbarManager(
-                            context,
-                            AllAppsActionManager(context, UI_HELPER_EXECUTOR) {
-                                PendingIntent(IIntentSender.Default())
-                            },
-                            object : TaskbarNavButtonCallbacks {},
-                        )
+                        object :
+                            TaskbarManager(
+                                context,
+                                AllAppsActionManager(context, UI_HELPER_EXECUTOR) {
+                                    PendingIntent(IIntentSender.Default())
+                                },
+                                object : TaskbarNavButtonCallbacks {},
+                            ) {
+                            override fun recreateTaskbar() {
+                                super.recreateTaskbar()
+                                if (currentActivityContext != null) injectControllers()
+                            }
+                        }
                     }
 
                 try {
@@ -154,7 +160,6 @@
                         taskbarManager.onUserUnlocked() // Required to complete initialization.
                     }
 
-                    injectControllers()
                     base.evaluate()
                 } finally {
                     // Revert Taskbar window.
@@ -168,10 +173,7 @@
     }
 
     /** Simulates Taskbar recreation lifecycle. */
-    fun recreateTaskbar() {
-        instrumentation.runOnMainSync { taskbarManager.recreateTaskbar() }
-        injectControllers()
-    }
+    fun recreateTaskbar() = instrumentation.runOnMainSync { taskbarManager.recreateTaskbar() }
 
     private fun injectControllers() {
         val controllers = activityContext.controllers
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 405dae7..46cafa7 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -177,8 +177,6 @@
      */
     @Test
     @PortraitLandscape
-    @ScreenRecordRule.ScreenRecord // b/338869019
-    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/338869019
     public void testAddDeleteShortcutOnHotseat() {
         mLauncher.getWorkspace()
                 .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))