Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7eff40ff authored by Sunny Goyal's avatar Sunny Goyal
Browse files

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
parent e9f31c10
Loading
Loading
Loading
Loading
+2 −6
Original line number Diff line number Diff line
@@ -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();
+51 −41
Original line number Diff line number Diff line
@@ -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,13 +160,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
    @Override
    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
        if (hasControlRemoteAppTransitionPermission()) {
            try {
            RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler) {

                @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
@@ -161,11 +175,16 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
                        mLauncher.getStateManager().setCurrentAnimation(anim);

                        anim.play(getIconAnimator(v));
                            if (launcherIsATargetWithMode(targetCompats, MODE_CLOSING)) {
                        if (launcherClosing) {
                            anim.play(getLauncherContentAnimator(false /* show */));
                        }
                        anim.play(getWindowAnimators(v, targetCompats));
                    }

                    if (launcherClosing) {
                        anim.addListener(mForceInvisibleListener);
                    }

                    return anim;
                }
            };
@@ -175,10 +194,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
            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.
            }
        }
        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 */));

//      TODO: App controlled transition for unlock to home TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER

            // TODO: 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
            }
        }
    }

@@ -575,7 +585,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
                    }
                }

                mLauncher.setForceInvisible(false);
                mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
                return anim;
            }
        };
+25 −10
Original line number Diff line number Diff line
@@ -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<T extends BaseDraggingActivity> {
        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<T extends BaseDraggingActivity> {
        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<T extends BaseDraggingActivity> {
        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<T extends BaseDraggingActivity> {
        if (!mWasLauncherAlreadyVisible) {
            mLauncherTransitionController = mActivityControlHelper
                    .createControllerForHiddenActivity(mActivity, mTransitionDragLength);
            mLauncherTransitionController.dispatchOnStart();
            mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
        }
    }
@@ -515,7 +518,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
    }

    public void onGestureStarted() {
        notifyGestureStarted();
        notifyGestureStartedAsync();
        setStateOnUiThread(STATE_GESTURE_STARTED);
        mGestureStarted = true;
        mRecentsAnimationWrapper.enableInputConsumer();
@@ -527,17 +530,29 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
     * 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();
+27 −6
Original line number Diff line number Diff line
@@ -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<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
    private final ArrayList<MultiWindowModeChangedListener> 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;
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -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 */);
    }

    /**