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
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user