From 7eff40ff2df3acea49aeba04dc78322a2b4b6208 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 11 Apr 2018 15:30:46 -0700 Subject: [PATCH] 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 --- .../launcher3/LauncherAnimationRunner.java | 8 +- .../LauncherAppTransitionManagerImpl.java | 88 +++++++++++-------- .../WindowTransformSwipeHandler.java | 35 +++++--- src/com/android/launcher3/BaseActivity.java | 33 +++++-- .../launcher3/LauncherStateManager.java | 2 +- 5 files changed, 104 insertions(+), 62 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java index f91933979e..cd673000d9 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 @@ public abstract class LauncherAnimationRunner extends AnimatorListenerAdapter @BinderThread @Override public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) { - postAtFrontOfQueueAsynchronously(mHandler, () -> { + mHandler.post(() -> { // Finish any previous animation finishSystemAnimation(); @@ -68,7 +65,6 @@ public abstract class LauncherAnimationRunner extends AnimatorListenerAdapter }); } - @UiThread public abstract AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats); @@ -87,7 +83,7 @@ public abstract class LauncherAnimationRunner extends AnimatorListenerAdapter @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 162035233d..299e7d51c1 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 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag } }; + 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 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag 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 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @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 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag 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 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag } } - 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 1255a02514..ce16adf93b 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.Build; 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.ViewTreeObserver.OnDrawListener; 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 @@ public class WindowTransformSwipeHandler { 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 @@ public class WindowTransformSwipeHandler { 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 @@ public class WindowTransformSwipeHandler { 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 @@ public class WindowTransformSwipeHandler { if (!mWasLauncherAlreadyVisible) { mLauncherTransitionController = mActivityControlHelper .createControllerForHiddenActivity(mActivity, mTransitionDragLength); + mLauncherTransitionController.dispatchOnStart(); mLauncherTransitionController.setPlayFraction(mCurrentShift.value); } } @@ -515,7 +518,7 @@ public class WindowTransformSwipeHandler { } public void onGestureStarted() { - notifyGestureStarted(); + notifyGestureStartedAsync(); setStateOnUiThread(STATE_GESTURE_STARTED); mGestureStarted = true; mRecentsAnimationWrapper.enableInputConsumer(); @@ -527,17 +530,29 @@ public class WindowTransformSwipeHandler { * 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 c15cde5f94..1f1ef9ad7f 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.DeviceProfile.OnDeviceProfileChangeListener; 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 mDPChangeListeners = new ArrayList<>(); private final ArrayList mMultiWindowModeChangedListeners = new ArrayList<>(); @@ -42,10 +57,11 @@ public abstract class BaseActivity extends Activity { 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 @@ public abstract class BaseActivity extends Activity { @Override protected void onStop() { mStarted = false; - mForceInvisible = false; + mForceInvisible = 0; super.onStop(); } @@ -153,15 +169,20 @@ public abstract class BaseActivity extends Activity { * 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 d5e6a9ddde..01166a15db 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -121,7 +121,7 @@ public class LauncherStateManager { * @see #goToState(LauncherState, boolean, Runnable) */ public void goToState(LauncherState state) { - goToState(state, mLauncher.isStarted() /* animated */, 0, null); + goToState(state, !mLauncher.isForceInvisible() && mLauncher.isStarted() /* animated */); } /**