Merge "Revert "fetch and update shortcut icons in background thread"" into ub-launcher3-master
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 5465480..826a275 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -88,6 +88,7 @@
         <activity android:name="com.android.quickstep.LockScreenRecentsActivity"
                   android:theme="@android:style/Theme.NoDisplay"
                   android:showOnLockScreen="true"
+                  android:taskAffinity="${packageName}.locktask"
                   android:directBootAware="true" />
 
     </application>
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 556f481..0eafb44 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -417,7 +417,8 @@
             return;
         }
 
-        TraceHelper.INSTANCE.beginFlagsOverride(TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
+        Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
+                TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
         MotionEvent event = (MotionEvent) ev;
         if (event.getAction() == ACTION_DOWN) {
             GestureState newGestureState = new GestureState(
@@ -446,7 +447,7 @@
 
         ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked());
         mUncheckedConsumer.onMotionEvent(event);
-        TraceHelper.INSTANCE.endFlagsOverride();
+        TraceHelper.INSTANCE.endFlagsOverride(traceToken);
     }
 
     private InputConsumer newConsumer(GestureState gestureState, boolean useSharedState,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 8dd1fff..1168758 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -367,13 +367,19 @@
         if (mWasLauncherAlreadyVisible) {
             mStateCallback.setState(STATE_LAUNCHER_DRAWN);
         } else {
-            TraceHelper.INSTANCE.beginSection("WTS-init");
+            Object traceToken = TraceHelper.INSTANCE.beginSection("WTS-init");
             View dragLayer = activity.getDragLayer();
             dragLayer.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
+                boolean mHandled = false;
 
                 @Override
                 public void onDraw() {
-                    TraceHelper.INSTANCE.endSection();
+                    if (mHandled) {
+                        return;
+                    }
+                    mHandled = true;
+
+                    TraceHelper.INSTANCE.endSection(traceToken);
                     dragLayer.post(() ->
                             dragLayer.getViewTreeObserver().removeOnDrawListener(this));
                     if (activity != mActivity) {
@@ -416,13 +422,14 @@
     private void initializeLauncherAnimationController() {
         buildAnimationController();
 
-        TraceHelper.INSTANCE.beginSection("logToggleRecents", TraceHelper.FLAG_IGNORE_BINDERS);
+        Object traceToken = TraceHelper.INSTANCE.beginSection("logToggleRecents",
+                TraceHelper.FLAG_IGNORE_BINDERS);
         // Only used in debug builds
         if (LatencyTrackerCompat.isEnabled(mContext)) {
             LatencyTrackerCompat.logToggleRecents(
                     (int) (mLauncherFrameDrawnTime - mTouchTimeMs));
         }
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
 
         // This method is only called when STATE_GESTURE_STARTED is set, so we can enable the
         // high-res thumbnail loader here once we are sure that we will end up in an overview state
@@ -1144,10 +1151,10 @@
             }
             if (!finishTransitionPosted) {
                 // If we haven't posted a draw callback, set the state immediately.
-                TraceHelper.INSTANCE.beginSection(SCREENSHOT_CAPTURED_EVT,
+                Object traceToken = TraceHelper.INSTANCE.beginSection(SCREENSHOT_CAPTURED_EVT,
                         TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS);
                 setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
-                TraceHelper.INSTANCE.endSection();
+                TraceHelper.INSTANCE.endSection(traceToken);
             }
         }
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index d231d51..02f4c40 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -198,7 +198,8 @@
 
         switch (ev.getActionMasked()) {
             case ACTION_DOWN: {
-                TraceHelper.INSTANCE.beginSection(DOWN_EVT, FLAG_CHECK_FOR_RACE_CONDITIONS);
+                Object traceToken = TraceHelper.INSTANCE.beginSection(DOWN_EVT,
+                        FLAG_CHECK_FOR_RACE_CONDITIONS);
                 mActivePointerId = ev.getPointerId(0);
                 mDownPos.set(ev.getX(), ev.getY());
                 mLastPos.set(mDownPos);
@@ -209,7 +210,7 @@
                     startTouchTrackingForWindowAnimation(ev.getEventTime(), false);
                 }
 
-                TraceHelper.INSTANCE.endSection();
+                TraceHelper.INSTANCE.endSection(traceToken);
                 break;
             }
             case ACTION_POINTER_DOWN: {
@@ -355,7 +356,8 @@
      * the animation can still be running.
      */
     private void finishTouchTracking(MotionEvent ev) {
-        TraceHelper.INSTANCE.beginSection(UP_EVT, FLAG_CHECK_FOR_RACE_CONDITIONS);
+        Object traceToken = TraceHelper.INSTANCE.beginSection(UP_EVT,
+                FLAG_CHECK_FOR_RACE_CONDITIONS);
 
         if (mPassedWindowMoveSlop && mInteractionHandler != null) {
             if (ev.getActionMasked() == ACTION_CANCEL) {
@@ -389,7 +391,7 @@
         mVelocityTracker.recycle();
         mVelocityTracker = null;
         mMotionPauseDetector.clear();
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
     }
 
     @Override
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 41f4a82..d270d76 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -248,6 +248,7 @@
     @Test
     @NavigationModeSwitch
     @PortraitLandscape
+    @Ignore("Temporarily disabled b/140252765")
     public void testQuickSwitchFromApp() throws Exception {
         startAppFast(getAppPackageName());
         startTestActivity(2);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index a19ba21..4b4d793 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -32,6 +32,7 @@
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
 import static com.android.launcher3.logging.LoggerUtils.newTarget;
 import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
+import static com.android.launcher3.testing.TestProtocol.CRASH_ADD_CUSTOM_SHORTCUT;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -112,6 +113,7 @@
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.qsb.QsbContainerView;
 import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
@@ -311,7 +313,8 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT, TraceHelper.FLAG_UI_EVENT);
+        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT,
+                TraceHelper.FLAG_UI_EVENT);
         if (DEBUG_STRICT_MODE) {
             StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                     .detectDiskReads()
@@ -429,7 +432,7 @@
             }
         });
 
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
     }
 
     protected LauncherOverlayManager getDefaultOverlay() {
@@ -934,14 +937,15 @@
 
     @Override
     protected void onStart() {
-        TraceHelper.INSTANCE.beginSection(ON_START_EVT, TraceHelper.FLAG_UI_EVENT);
+        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_START_EVT,
+                TraceHelper.FLAG_UI_EVENT);
         super.onStart();
         if (!mDeferOverlayCallbacks) {
             mOverlayManager.onActivityStarted(this);
         }
 
         mAppWidgetHost.setListenIfResumed(true);
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
     }
 
     private void handleDeferredResume() {
@@ -1036,7 +1040,8 @@
 
     @Override
     protected void onResume() {
-        TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT, TraceHelper.FLAG_UI_EVENT);
+        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT,
+                TraceHelper.FLAG_UI_EVENT);
         super.onResume();
 
         mHandler.removeCallbacks(mHandleDeferredResume);
@@ -1057,7 +1062,7 @@
             mOverlayManager.onActivityResumed(this);
         }
 
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
     }
 
     @Override
@@ -1207,8 +1212,13 @@
      */
     private void completeAddShortcut(Intent data, int container, int screenId, int cellX,
             int cellY, PendingRequestArgs args) {
-        if (args.getRequestCode() != REQUEST_CREATE_SHORTCUT
+        if (data == null
+                || args.getRequestCode() != REQUEST_CREATE_SHORTCUT
                 || args.getPendingIntent().getComponent() == null) {
+            if (data == null && TestProtocol.sDebugTracing) {
+                Log.d(CRASH_ADD_CUSTOM_SHORTCUT,
+                        "Failed to add custom shortcut: Intent is null, args = " + args);
+            }
             return;
         }
 
@@ -1416,7 +1426,7 @@
 
     @Override
     protected void onNewIntent(Intent intent) {
-        TraceHelper.INSTANCE.beginSection(ON_NEW_INTENT_EVT);
+        Object traceToken = TraceHelper.INSTANCE.beginSection(ON_NEW_INTENT_EVT);
         super.onNewIntent(intent);
 
         boolean alreadyOnHome = hasWindowFocus() && ((intent.getFlags() &
@@ -1468,7 +1478,7 @@
             mOverlayManager.hideOverlay(isStarted() && !isForceInvisible());
         }
 
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
     }
 
     @Override
@@ -1971,7 +1981,7 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void startBinding() {
-        TraceHelper.INSTANCE.beginSection("startBinding");
+        Object traceToken = TraceHelper.INSTANCE.beginSection("startBinding");
         // Floating panels (except the full widget sheet) are associated with individual icons. If
         // we are starting a fresh bind, close all such panels as all the icons are about
         // to go away.
@@ -1989,7 +1999,7 @@
         if (mHotseat != null) {
             mHotseat.resetLayout(getWallpaperDeviceProfile().isVerticalBarLayout());
         }
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
     }
 
     @Override
@@ -2189,7 +2199,7 @@
             return view;
         }
 
-        TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
+        Object traceToken = TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
 
         try {
             final LauncherAppWidgetProviderInfo appWidgetInfo;
@@ -2286,7 +2296,7 @@
             }
             prepareAppWidget(view, item);
         } finally {
-            TraceHelper.INSTANCE.endSection();
+            TraceHelper.INSTANCE.endSection(traceToken);
         }
 
         return view;
@@ -2366,7 +2376,7 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void finishBindingItems(int pageBoundFirst) {
-        TraceHelper.INSTANCE.beginSection("finishBindingItems");
+        Object traceToken = TraceHelper.INSTANCE.beginSection("finishBindingItems");
         mWorkspace.restoreInstanceStateForRemainingPages();
 
         setWorkspaceLoading(false);
@@ -2390,7 +2400,7 @@
                 mDeviceProfile.inv.numFolderColumns * mDeviceProfile.inv.numFolderRows);
         getViewCache().setCacheSize(R.layout.folder_page, 2);
 
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
     }
 
     private boolean canRunNewAppsAnimation() {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 3673102..81b701d 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -180,8 +180,17 @@
                     "LoaderTask2 " + this);
         }
 
-        TraceHelper.INSTANCE.beginSection(TAG);
-        TimingLogger logger = new TimingLogger(TAG, "run");
+        Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
+        TimingLogger logger = TestProtocol.sDebugTracing ?
+                new TimingLogger(TAG, "run") {
+                    @Override
+                    public void addSplit(String splitLabel) {
+                        super.addSplit(splitLabel);
+                        Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE,
+                                "LoaderTask.addSplit " + splitLabel);
+                    }
+                }
+                : new TimingLogger(TAG, "run");
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
             List<ShortcutInfo> allShortcuts = new ArrayList<>();
             loadWorkspace(allShortcuts);
@@ -272,7 +281,7 @@
         } finally {
             logger.dumpToLog();
         }
-        TraceHelper.INSTANCE.endSection();
+        TraceHelper.INSTANCE.endSection(traceToken);
     }
 
     public synchronized void stopLocked() {
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index faf0ff6..923c466 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -86,4 +86,5 @@
     public static final String APP_NOT_DISABLED = "b/139891609";
     public static final String NO_CONTEXT_MENU = "b/141770616";
     public static final String LAUNCHER_DIDNT_INITIALIZE = "b/142514365";
+    public static final String CRASH_ADD_CUSTOM_SHORTCUT = "b/141568904";
 }
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index d0edfd8..c38ca24 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -330,8 +330,7 @@
     private void initializeDragging() {
         if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
             mSubtractDisplacement = 0;
-        }
-        if (mDisplacement > 0) {
+        } else if (mDisplacement > 0) {
             mSubtractDisplacement = mTouchSlop;
         } else {
             mSubtractDisplacement = -mTouchSlop;
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index 073fb6a..168227d 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -46,35 +46,44 @@
      */
     public static TraceHelper INSTANCE = new TraceHelper();
 
-    public void beginSection(String sectionName) {
-        beginSection(sectionName, 0);
+    /**
+     * @return a token to pass into {@link #endSection(Object)}.
+     */
+    public Object beginSection(String sectionName) {
+        return beginSection(sectionName, 0);
     }
 
-    public void beginSection(String sectionName, int flags) {
+    public Object beginSection(String sectionName, int flags) {
         Trace.beginSection(sectionName);
+        return null;
     }
 
-    public void endSection() {
+    /**
+     * @param token the token returned from {@link #beginSection(String, int)}
+     */
+    public void endSection(Object token) {
         Trace.endSection();
     }
 
     /**
      * Similar to {@link #beginSection} but doesn't add a trace section.
      */
-    public void beginFlagsOverride(int flags) { }
+    public Object beginFlagsOverride(int flags) {
+        return null;
+    }
 
-    public void endFlagsOverride() { }
+    public void endFlagsOverride(Object token) { }
 
     /**
      * Temporarily ignore blocking binder calls for the duration of this {@link Supplier}.
      */
     @MainThread
     public static <T> T whitelistIpcs(String rpcName, Supplier<T> supplier) {
-        INSTANCE.beginSection(rpcName, FLAG_IGNORE_BINDERS);
+        Object traceToken = INSTANCE.beginSection(rpcName, FLAG_IGNORE_BINDERS);
         try {
             return supplier.get();
         } finally {
-            INSTANCE.endSection();
+            INSTANCE.endSection(traceToken);
         }
     }
 }
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 709822b..5e87612 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -24,8 +24,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import android.util.Log;
-
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -38,7 +36,6 @@
 import com.android.launcher3.tapl.AppIconMenuItem;
 import com.android.launcher3.tapl.Widgets;
 import com.android.launcher3.tapl.Workspace;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.launcher3.views.OptionsPopupView;
 import com.android.launcher3.widget.WidgetsFullSheet;
 import com.android.launcher3.widget.WidgetsRecyclerView;
@@ -349,6 +346,7 @@
      * Custom shortcuts are replaced by deep shortcuts after api 25.
      */
     @Test
+    @Ignore("Temporarily disabled to unblock merging to master")
     @PortraitLandscape
     public void testDragCustomShortcut() {
         mLauncher.getWorkspace().openAllWidgets()
@@ -361,10 +359,4 @@
     public static String getAppPackageName() {
         return getInstrumentation().getContext().getPackageName();
     }
-
-    @Test
-    @Stability
-    public void testTestStabilityAttribute() {
-        Log.d("TestStabilityRule", "Hello world!");
-    }
 }
diff --git a/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java b/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java
index d156d1f..59f2173 100644
--- a/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java
+++ b/tests/src/com/android/launcher3/util/RaceConditionReproducerTest.java
@@ -22,6 +22,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -45,6 +46,11 @@
         eventProcessor = new RaceConditionReproducer();
     }
 
+    @After
+    public void tearDown() {
+        TraceHelperForTest.cleanup();
+    }
+
     private void run3_3_TestAction() throws InterruptedException {
         Thread tb = new Thread(() -> {
             eventProcessor.onEvent("B1");
@@ -125,9 +131,7 @@
     @Test
     // 2 threads, 3 events each; reproducing a particular event sequence.
     public void test3_3_ReproMode() throws Exception {
-        final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(
-                SOME_VALID_SEQUENCE_3_3);
-
+        eventProcessor = new RaceConditionReproducer(SOME_VALID_SEQUENCE_3_3);
         eventProcessor.startIteration();
         run3_3_TestAction();
         assertTrue(!eventProcessor.finishIteration());
diff --git a/tests/src/com/android/launcher3/util/TraceHelperForTest.java b/tests/src/com/android/launcher3/util/TraceHelperForTest.java
index 9125f5f..f1c8a67 100644
--- a/tests/src/com/android/launcher3/util/TraceHelperForTest.java
+++ b/tests/src/com/android/launcher3/util/TraceHelperForTest.java
@@ -33,6 +33,11 @@
         INSTANCE_FOR_TEST.mRaceConditionReproducer = reproducer;
     }
 
+    public static void cleanup() {
+        INSTANCE_FOR_TEST.mRaceConditionReproducer = null;
+        INSTANCE_FOR_TEST.mFlagsChangeListener = null;
+    }
+
     public static void setFlagsChangeListener(IntConsumer listener) {
         TraceHelper.INSTANCE = INSTANCE_FOR_TEST;
         INSTANCE_FOR_TEST.mFlagsChangeListener = listener;
@@ -41,9 +46,10 @@
     private TraceHelperForTest() { }
 
     @Override
-    public void beginSection(String sectionName, int flags) {
+    public Object beginSection(String sectionName, int flags) {
         LinkedList<TraceInfo> stack = mStack.get();
-        stack.add(new TraceInfo(sectionName, flags));
+        TraceInfo info = new TraceInfo(sectionName, flags);
+        stack.add(info);
 
         if ((flags & TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS) != 0
                  && mRaceConditionReproducer != null) {
@@ -52,39 +58,49 @@
         updateBinderTracking(stack);
 
         super.beginSection(sectionName, flags);
+        return info;
     }
 
     @Override
-    public void endSection() {
+    public void endSection(Object token) {
         LinkedList<TraceInfo> stack = mStack.get();
-        TraceInfo info = stack.pollLast();
+        if (stack.size() == 0) {
+            new Throwable().printStackTrace();
+        }
+        TraceInfo info = (TraceInfo) token;
+        stack.remove(info);
         if ((info.flags & TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS) != 0
                 && mRaceConditionReproducer != null) {
             mRaceConditionReproducer.onEvent(RaceConditionReproducer.exitEvt(info.sectionName));
         }
         updateBinderTracking(stack);
 
-        super.endSection();
+        super.endSection(token);
     }
 
     @Override
-    public void beginFlagsOverride(int flags) {
+    public Object beginFlagsOverride(int flags) {
         LinkedList<TraceInfo> stack = mStack.get();
-        stack.push(new TraceInfo(null, flags));
+        TraceInfo info = new TraceInfo(null, flags);
+        stack.add(info);
         updateBinderTracking(stack);
         super.beginFlagsOverride(flags);
+        return info;
     }
 
     @Override
-    public void endFlagsOverride() {
-        super.endFlagsOverride();
-        updateBinderTracking(mStack.get());
+    public void endFlagsOverride(Object token) {
+        super.endFlagsOverride(token);
+        LinkedList<TraceInfo> stack = mStack.get();
+        TraceInfo info = (TraceInfo) token;
+        stack.remove(info);
+        updateBinderTracking(stack);
     }
 
     private void updateBinderTracking(LinkedList<TraceInfo> stack) {
         if (mFlagsChangeListener != null) {
             mFlagsChangeListener.accept(stack.stream()
-                    .mapToInt(s -> s.flags).reduce(0, (a, b) -> a | b));
+                    .mapToInt(info -> info.flags).reduce(0, (a, b) -> a | b));
         }
     }
 
diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index d7f41bf..69bf01d 100644
--- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -17,6 +17,7 @@
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
+import android.content.pm.PackageManager;
 import android.os.Build;
 import android.util.Log;
 
@@ -50,20 +51,33 @@
                     + "(?<postsubmit>[0-9]+)"
                     + ")$");
 
+    public static final int LOCAL = 0x1;
+    public static final int UNBUNDLED_PRESUBMIT = 0x2;
+    public static final int UNBUNDLED_POSTSUBMIT = 0x4;
+    public static final int PLATFORM_PRESUBMIT = 0x8;
+    public static final int PLATFORM_POSTSUBMIT = 0x10;
+
+    private static final int RUN_FLAFOR = getRunFlavor();
+
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.METHOD)
     public @interface Stability {
+        int flavors();
     }
 
     @Override
     public Statement apply(Statement base, Description description) {
-        if (description.getAnnotation(Stability.class) != null) {
+        final Stability stability = description.getAnnotation(Stability.class);
+        if (stability != null) {
             return new Statement() {
                 @Override
                 public void evaluate() throws Throwable {
-                    getRunFlavor();
-
-                    base.evaluate();
+                    if ((stability.flavors() & RUN_FLAFOR) != 0) {
+                        Log.d(TAG, "Running " + description.getDisplayName());
+                        base.evaluate();
+                    } else {
+                        Log.d(TAG, "Skipping " + description.getDisplayName());
+                    }
                 }
             };
         } else {
@@ -71,49 +85,63 @@
         }
     }
 
-    private static void getRunFlavor() throws Exception {
-        final String launcherVersion = getInstrumentation().
-                getContext().
-                getPackageManager().
-                getPackageInfo(
-                        UiDevice.getInstance(getInstrumentation()).
-                                getLauncherPackageName(),
-                        0).
-                versionName;
+    private static int getRunFlavor() {
+        final String launcherVersion;
+        try {
+            launcherVersion = getInstrumentation().
+                    getContext().
+                    getPackageManager().
+                    getPackageInfo(
+                            UiDevice.getInstance(getInstrumentation()).
+                                    getLauncherPackageName(),
+                            0).
+                    versionName;
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
 
         final Matcher launcherBuildMatcher = LAUNCHER_BUILD.matcher(launcherVersion);
 
         if (!launcherBuildMatcher.find()) {
-            Log.e(TAG, "Match not found");
+            throw new AssertionError("Launcher build match not found");
         }
 
         final String platformVersion = Build.VERSION.INCREMENTAL;
         final Matcher platformBuildMatcher = PLATFORM_BUILD.matcher(platformVersion);
 
         if (!platformBuildMatcher.find()) {
-            Log.e(TAG, "Match not found");
+            throw new AssertionError("Platform build match not found");
         }
 
         Log.d(TAG, "Launcher: " + launcherVersion + ", platform: " + platformVersion);
 
+        final int runFlavor;
+
         if (launcherBuildMatcher.group("local") != null && (
                 platformBuildMatcher.group("commandLine") != null ||
                         platformBuildMatcher.group("postsubmit") != null)) {
             Log.d(TAG, "LOCAL RUN");
+            runFlavor = LOCAL;
         } else if (launcherBuildMatcher.group("presubmit") != null
                 && platformBuildMatcher.group("postsubmit") != null) {
             Log.d(TAG, "UNBUNDLED PRESUBMIT");
+            runFlavor = UNBUNDLED_PRESUBMIT;
         } else if (launcherBuildMatcher.group("postsubmit") != null
                 && platformBuildMatcher.group("postsubmit") != null) {
             Log.d(TAG, "UNBUNDLED POSTSUBMIT");
+            runFlavor = UNBUNDLED_POSTSUBMIT;
         } else if (launcherBuildMatcher.group("platform") != null
                 && platformBuildMatcher.group("presubmit") != null) {
             Log.d(TAG, "PLATFORM PRESUBMIT");
+            runFlavor = PLATFORM_PRESUBMIT;
         } else if (launcherBuildMatcher.group("platform") != null
                 && platformBuildMatcher.group("postsubmit") != null) {
             Log.d(TAG, "PLATFORM POSTSUBMIT");
+            runFlavor = PLATFORM_POSTSUBMIT;
         } else {
-            Log.e(TAG, "ERROR3");
+            throw new AssertionError("Unrecognized run flavor");
         }
+
+        return runFlavor;
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 8b5792c..0d9038f 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -137,15 +137,29 @@
     }
 
     protected void quickSwitchToPreviousApp(int expectedState) {
+        boolean transposeInLandscape = false;
         switch (mLauncher.getNavigationModel()) {
-            case ZERO_BUTTON:
+            case TWO_BUTTON:
+                transposeInLandscape = true;
                 // Fall through, zero button and two button modes behave the same.
-            case TWO_BUTTON: {
-                // Swipe from the bottom left to the bottom right of the screen.
-                final int startX = 0;
-                final int startY = getSwipeStartY();
-                final int endX = mLauncher.getDevice().getDisplayWidth();
-                final int endY = startY;
+            case ZERO_BUTTON: {
+                final int startX;
+                final int startY;
+                final int endX;
+                final int endY;
+                if (mLauncher.getDevice().isNaturalOrientation() || !transposeInLandscape) {
+                    // Swipe from the bottom left to the bottom right of the screen.
+                    startX = 0;
+                    startY = getSwipeStartY();
+                    endX = mLauncher.getDevice().getDisplayWidth();
+                    endY = startY;
+                } else {
+                    // Swipe from the bottom right to the top right of the screen.
+                    startX = getSwipeStartX();
+                    startY = mLauncher.getRealDisplaySize().y - 1;
+                    endX = startX;
+                    endY = 0;
+                }
                 mLauncher.swipeToState(startX, startY, endX, endY, 20, expectedState);
                 break;
             }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 484cbb6..321f727 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -497,7 +497,7 @@
     }
 
     public void waitForLauncherInitialized() {
-        for (int i = 0; i < 100; ++i) {
+        for (int i = 0; i < 600; ++i) {
             if (getTestInfo(
                     TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED).
                     getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD)) {