Several app transition fixes:

> If launcher already started, creating the state transition only after threshold crossed, so that previous animations are not cancelled
> Not posting animaiton callbacks at the front of the queue, as that sometimes causes it get executed before onNewIntent
> Farking the activity as forceInvisible while launching an opaque app, so that quickly pressing home/back runs the reverse animation
> Not running state animations when force-invisible is true

Bug: 77830325
Bug: 77898806
Change-Id: I50a7e915ca35fd6aeb284c8f321ecca74396fe98
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index f919339..cd67300 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -15,9 +15,6 @@
  */
 package com.android.launcher3;
 
-import static com.android.systemui.shared.recents.utilities.Utilities
-        .postAtFrontOfQueueAsynchronously;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -49,7 +46,7 @@
     @BinderThread
     @Override
     public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) {
-        postAtFrontOfQueueAsynchronously(mHandler, () -> {
+        mHandler.post(() -> {
             // Finish any previous animation
             finishSystemAnimation();
 
@@ -68,7 +65,6 @@
         });
     }
 
-
     @UiThread
     public abstract AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats);
 
@@ -87,7 +83,7 @@
     @BinderThread
     @Override
     public void onAnimationCancelled() {
-        postAtFrontOfQueueAsynchronously(mHandler, () -> {
+        mHandler.post(() -> {
             if (mAnimator != null) {
                 mAnimator.removeListener(this);
                 mAnimator.end();
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 1620352..299e7d5 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
+import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
@@ -119,6 +121,18 @@
         }
     };
 
+    private final AnimatorListenerAdapter mForceInvisibleListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mLauncher.addForceInvisibleFlag(INVISIBLE_BY_APP_TRANSITIONS);
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mLauncher.clearForceInvisibleFlag(INVISIBLE_BY_APP_TRANSITIONS);
+        }
+    };
+
     public LauncherAppTransitionManagerImpl(Context context) {
         mLauncher = Launcher.getLauncher(context);
         mDragLayer = mLauncher.getDragLayer();
@@ -126,7 +140,6 @@
         mIsRtl = Utilities.isRtl(mLauncher.getResources());
         mDeviceProfile = mLauncher.getDeviceProfile();
 
-
         Resources res = mLauncher.getResources();
         mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
         mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
@@ -147,38 +160,40 @@
     @Override
     public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
         if (hasControlRemoteAppTransitionPermission()) {
-            try {
-                RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler) {
+            RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler) {
 
-                    @Override
-                    public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
-                        AnimatorSet anim = new AnimatorSet();
+                @Override
+                public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
+                    AnimatorSet anim = new AnimatorSet();
 
+                    boolean launcherClosing =
+                            launcherIsATargetWithMode(targetCompats, MODE_CLOSING);
 
-                        if (!composeRecentsLaunchAnimator(v, targetCompats, anim)) {
-                            // Set the state animation first so that any state listeners are called
-                            // before our internal listeners.
-                            mLauncher.getStateManager().setCurrentAnimation(anim);
+                    if (!composeRecentsLaunchAnimator(v, targetCompats, anim)) {
+                        // Set the state animation first so that any state listeners are called
+                        // before our internal listeners.
+                        mLauncher.getStateManager().setCurrentAnimation(anim);
 
-                            anim.play(getIconAnimator(v));
-                            if (launcherIsATargetWithMode(targetCompats, MODE_CLOSING)) {
-                                anim.play(getLauncherContentAnimator(false /* show */));
-                            }
-                            anim.play(getWindowAnimators(v, targetCompats));
+                        anim.play(getIconAnimator(v));
+                        if (launcherClosing) {
+                            anim.play(getLauncherContentAnimator(false /* show */));
                         }
-                        return anim;
+                        anim.play(getWindowAnimators(v, targetCompats));
                     }
-                };
 
-                int duration = findTaskViewToLaunch(launcher, v, null) != null
-                        ? RECENTS_LAUNCH_DURATION : APP_LAUNCH_DURATION;
-                int statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION;
-                return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
-                        runner, duration, statusBarTransitionDelay));
-            } catch (NoClassDefFoundError e) {
-                // Gracefully fall back to default launch options if the user's platform doesn't
-                // have the latest changes.
-            }
+                    if (launcherClosing) {
+                        anim.addListener(mForceInvisibleListener);
+                    }
+
+                    return anim;
+                }
+            };
+
+            int duration = findTaskViewToLaunch(launcher, v, null) != null
+                    ? RECENTS_LAUNCH_DURATION : APP_LAUNCH_DURATION;
+            int statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION;
+            return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
+                    runner, duration, statusBarTransitionDelay));
         }
         return getDefaultActivityLaunchOptions(launcher, v);
     }
@@ -521,19 +536,14 @@
     private void registerRemoteAnimations() {
         // Unregister this
         if (hasControlRemoteAppTransitionPermission()) {
-            try {
-                RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
-                definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
-                        WindowManagerWrapper.ACTIVITY_TYPE_STANDARD,
-                        new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(),
-                                CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+            RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
+            definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
+                    WindowManagerWrapper.ACTIVITY_TYPE_STANDARD,
+                    new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(),
+                            CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
 
-//      TODO: App controlled transition for unlock to home TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
-
-                new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
-            } catch (NoClassDefFoundError e) {
-                // Gracefully fall back if the user's platform doesn't have the latest changes
-            }
+            // TODO: Transition for unlock to home TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
+            new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
         }
     }
 
@@ -575,7 +585,7 @@
                     }
                 }
 
-                mLauncher.setForceInvisible(false);
+                mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
                 return anim;
             }
         };
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 1255a02..ce16adf 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -15,6 +15,7 @@
  */
 package com.android.quickstep;
 
+import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_START_DURATION;
@@ -38,6 +39,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.support.annotation.AnyThread;
 import android.support.annotation.UiThread;
 import android.support.annotation.WorkerThread;
 import android.util.Log;
@@ -46,6 +48,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseActivity;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherAppState;
@@ -208,7 +211,7 @@
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
                 this::launcherFrameDrawn);
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
-                this::notifyGestureStarted);
+                this::onGestureStartedWithLauncher);
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
                         | STATE_GESTURE_CANCELLED,
                 this::resetStateForAnimationCancel);
@@ -290,7 +293,11 @@
         mActivity = activity;
         // Override the visibility of the activity until the gesture actually starts and we swipe
         // up, or until we transition home and the home animation is composed
-        mActivity.setForceInvisible(true);
+        if (alreadyOnHome) {
+            mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
+        } else {
+            mActivity.addForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
+        }
 
         mRecentsView = activity.getOverviewPanel();
         mQuickScrubController = mRecentsView.getQuickScrubController();
@@ -317,11 +324,6 @@
         AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);
 
         if (mWasLauncherAlreadyVisible) {
-            mLauncherTransitionController = mActivityControlHelper
-                    .createControllerForVisibleActivity(activity);
-            mLauncherTransitionController.dispatchOnStart();
-            mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
-
             mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_DRAWN);
         } else {
             TraceHelper.beginSection("WTS-init");
@@ -420,6 +422,7 @@
         if (!mWasLauncherAlreadyVisible) {
             mLauncherTransitionController = mActivityControlHelper
                     .createControllerForHiddenActivity(mActivity, mTransitionDragLength);
+            mLauncherTransitionController.dispatchOnStart();
             mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
         }
     }
@@ -515,7 +518,7 @@
     }
 
     public void onGestureStarted() {
-        notifyGestureStarted();
+        notifyGestureStartedAsync();
         setStateOnUiThread(STATE_GESTURE_STARTED);
         mGestureStarted = true;
         mRecentsAnimationWrapper.enableInputConsumer();
@@ -527,17 +530,29 @@
      * Notifies the launcher that the swipe gesture has started. This can be called multiple times
      * on both background and UI threads
      */
-    private void notifyGestureStarted() {
+    @AnyThread
+    private void notifyGestureStartedAsync() {
         final T curActivity = mActivity;
         if (curActivity != null) {
             // Once the gesture starts, we can no longer transition home through the button, so
             // reset the force override of the activity visibility
-            mActivity.setForceInvisible(false);
+            mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
             mActivityControlHelper.onQuickstepGestureStarted(
                     curActivity, mWasLauncherAlreadyVisible);
         }
     }
 
+    private void onGestureStartedWithLauncher() {
+        notifyGestureStartedAsync();
+
+        if (mWasLauncherAlreadyVisible) {
+            mLauncherTransitionController = mActivityControlHelper
+                    .createControllerForVisibleActivity(mActivity);
+            mLauncherTransitionController.dispatchOnStart();
+            mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
+        }
+    }
+
     @WorkerThread
     public void onGestureEnded(float endVelocity) {
         Resources res = mContext.getResources();
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index c15cde5..1f1ef9a 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -16,12 +16,15 @@
 
 package com.android.launcher3;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
 import android.app.Activity;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Point;
+import android.support.annotation.IntDef;
 import android.view.Display;
 import android.view.View.AccessibilityDelegate;
 
@@ -29,10 +32,22 @@
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.util.SystemUiController;
 
+import java.lang.annotation.Retention;
 import java.util.ArrayList;
 
 public abstract class BaseActivity extends Activity {
 
+    public static final int INVISIBLE_BY_STATE_HANDLER = 1 << 0;
+    public static final int INVISIBLE_BY_APP_TRANSITIONS = 1 << 1;
+    public static final int INVISIBLE_ALL =
+            INVISIBLE_BY_STATE_HANDLER | INVISIBLE_BY_APP_TRANSITIONS;
+
+    @Retention(SOURCE)
+    @IntDef(
+            flag = true,
+            value = {INVISIBLE_BY_STATE_HANDLER, INVISIBLE_BY_APP_TRANSITIONS})
+    public @interface InvisibilityFlags{}
+
     private final ArrayList<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
     private final ArrayList<MultiWindowModeChangedListener> mMultiWindowModeChangedListeners =
             new ArrayList<>();
@@ -42,10 +57,11 @@
     protected SystemUiController mSystemUiController;
 
     private boolean mStarted;
+    private boolean mUserActive;
+
     // When the recents animation is running, the visibility of the Launcher is managed by the
     // animation
-    private boolean mForceInvisible;
-    private boolean mUserActive;
+    @InvisibilityFlags private int mForceInvisible;
 
     public DeviceProfile getDeviceProfile() {
         return mDeviceProfile;
@@ -114,7 +130,7 @@
     @Override
     protected void onStop() {
         mStarted = false;
-        mForceInvisible = false;
+        mForceInvisible = 0;
         super.onStop();
     }
 
@@ -153,15 +169,20 @@
      * recents animation.
      * @see LauncherAppTransitionManagerImpl.getWallpaperOpenRunner()
      */
-    public void setForceInvisible(boolean invisible) {
-        mForceInvisible = invisible;
+    public void addForceInvisibleFlag(@InvisibilityFlags int flag) {
+        mForceInvisible |= flag;
     }
 
+    public void clearForceInvisibleFlag(@InvisibilityFlags int flag) {
+        mForceInvisible &= ~flag;
+    }
+
+
     /**
      * @return Wether this activity should be considered invisible regardless of actual visibility.
      */
     public boolean isForceInvisible() {
-        return mForceInvisible;
+        return mForceInvisible != 0;
     }
 
     /**
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index d5e6a9d..01166a1 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -121,7 +121,7 @@
      * @see #goToState(LauncherState, boolean, Runnable)
      */
     public void goToState(LauncherState state) {
-        goToState(state, mLauncher.isStarted() /* animated */, 0, null);
+        goToState(state, !mLauncher.isForceInvisible() && mLauncher.isStarted() /* animated */);
     }
 
     /**