Finish recents animation when starting a new activity

- Defer starting the activity when an activity is paused, and finish
  the current animation to trigger launcher to be resumed

Bug: 132811175
Test: Swipe up and launch a new app
Change-Id: I78b76800052512eb93f69ccf0523f4d752a82ece
This commit is contained in:
Winson Chung 2019-06-17 22:34:33 -07:00
parent a730a233b8
commit 0b70cd4ca4
10 changed files with 63 additions and 30 deletions

View File

@ -89,4 +89,6 @@ public abstract class RecentsUiFactory {
public static RotationMode getRotationMode(DeviceProfile dp) {
return RotationMode.NORMAL;
}
public static void clearSwipeSharedState(boolean finishAnimation) {}
}

View File

@ -46,6 +46,7 @@ import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.WindowManagerWrapper;
@ -183,6 +184,13 @@ public abstract class RecentsUiFactory {
return new RecentsViewStateController(launcher);
}
/**
* Clears the swipe shared state for the current swipe gesture.
*/
public static void clearSwipeSharedState(boolean finishAnimation) {
TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation);
}
/**
* Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
*

View File

@ -72,13 +72,15 @@ public class SwipeSharedState implements SwipeAnimationListener {
mLastAnimationRunning = false;
}
private void clearListenerState() {
private void clearListenerState(boolean finishAnimation) {
if (mRecentsAnimationListener != null) {
mRecentsAnimationListener.removeListener(this);
mRecentsAnimationListener.cancelListener();
if (mLastAnimationRunning && mLastAnimationTarget != null) {
Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(),
mLastAnimationTarget::cancelAnimation);
finishAnimation
? mLastAnimationTarget::finishAnimation
: mLastAnimationTarget::cancelAnimation);
mLastAnimationTarget = null;
}
}
@ -106,7 +108,7 @@ public class SwipeSharedState implements SwipeAnimationListener {
}
}
clearListenerState();
clearListenerState(false /* finishAnimation */);
boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false
: mOverviewComponentObserver.getActivityControlHelper().shouldMinimizeSplitScreen();
mRecentsAnimationListener = new RecentsAnimationListenerSet(
@ -138,8 +140,8 @@ public class SwipeSharedState implements SwipeAnimationListener {
mLastAnimationTarget = mLastAnimationTarget.cloneWithoutTargets();
}
public void clearAllState() {
clearListenerState();
public void clearAllState(boolean finishAnimation) {
clearListenerState(finishAnimation);
canGestureBeContinued = false;
recentsAnimationFinishInterrupted = false;
nextRunningTaskId = -1;

View File

@ -225,14 +225,18 @@ public class TouchInteractionService extends Service implements
};
private static boolean sConnected = false;
private static final SwipeSharedState sSwipeSharedState = new SwipeSharedState();
public static boolean isConnected() {
return sConnected;
}
private final SwipeSharedState mSwipeSharedState = new SwipeSharedState();
public static SwipeSharedState getSwipeSharedState() {
return sSwipeSharedState;
}
private final InputConsumer mResetGestureInputConsumer =
new ResetGestureInputConsumer(mSwipeSharedState);
new ResetGestureInputConsumer(sSwipeSharedState);
private ActivityManagerWrapper mAM;
private RecentsModel mRecentsModel;
@ -436,7 +440,7 @@ public class TouchInteractionService extends Service implements
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
mIsUserUnlocked = true;
mSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver);
sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver);
mInputConsumer.registerInputConsumer();
onSystemUiProxySet();
onSystemUiFlagsChanged();
@ -589,7 +593,7 @@ public class TouchInteractionService extends Service implements
private InputConsumer newBaseConsumer(boolean useSharedState, MotionEvent event) {
final RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
if (!useSharedState) {
mSwipeSharedState.clearAllState();
sSwipeSharedState.clearAllState(false /* finishAnimation */);
}
if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) {
// This handles apps showing over the lockscreen (e.g. camera)
@ -599,16 +603,16 @@ public class TouchInteractionService extends Service implements
final ActivityControlHelper activityControl =
mOverviewComponentObserver.getActivityControlHelper();
if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher
&& !mSwipeSharedState.recentsAnimationFinishInterrupted) {
if (runningTaskInfo == null && !sSwipeSharedState.goingToLauncher
&& !sSwipeSharedState.recentsAnimationFinishInterrupted) {
return mResetGestureInputConsumer;
} else if (mSwipeSharedState.recentsAnimationFinishInterrupted) {
} else if (sSwipeSharedState.recentsAnimationFinishInterrupted) {
// If the finish animation was interrupted, then continue using the other activity input
// consumer but with the next task as the running task
RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
info.id = mSwipeSharedState.nextRunningTaskId;
info.id = sSwipeSharedState.nextRunningTaskId;
return createOtherActivityInputConsumer(event, info);
} else if (mSwipeSharedState.goingToLauncher || activityControl.isResumed()) {
} else if (sSwipeSharedState.goingToLauncher || activityControl.isResumed()) {
return createOverviewInputConsumer(event);
} else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) {
return createOverviewInputConsumer(event);
@ -617,7 +621,7 @@ public class TouchInteractionService extends Service implements
return mResetGestureInputConsumer;
} else if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
return new FallbackNoButtonInputConsumer(this, activityControl,
mInputMonitorCompat, mSwipeSharedState, mSwipeTouchRegion,
mInputMonitorCompat, sSwipeSharedState, mSwipeTouchRegion,
mOverviewComponentObserver, disableHorizontalSwipe(event), runningTaskInfo);
} else {
return createOtherActivityInputConsumer(event, runningTaskInfo);
@ -640,13 +644,13 @@ public class TouchInteractionService extends Service implements
return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel,
mOverviewComponentObserver.getOverviewIntent(), activityControl,
shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive,
mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
disableHorizontalSwipe(event));
}
private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) {
if (mMode == Mode.NO_BUTTON && taskInfo != null) {
return new DeviceLockedInputConsumer(this, mSwipeSharedState, mInputMonitorCompat,
return new DeviceLockedInputConsumer(this, sSwipeSharedState, mInputMonitorCompat,
mSwipeTouchRegion, taskInfo.taskId);
} else {
return mResetGestureInputConsumer;
@ -661,7 +665,7 @@ public class TouchInteractionService extends Service implements
return mResetGestureInputConsumer;
}
if (activity.getRootView().hasWindowFocus() || mSwipeSharedState.goingToLauncher) {
if (activity.getRootView().hasWindowFocus() || sSwipeSharedState.goingToLauncher) {
return new OverviewInputConsumer(activity, mInputMonitorCompat,
false /* startingInActivityBounds */);
} else {
@ -708,7 +712,7 @@ public class TouchInteractionService extends Service implements
+ mOverviewComponentObserver.getActivityControlHelper().isResumed());
pw.println(" useSharedState=" + mConsumer.useSharedSwipeState());
if (mConsumer.useSharedSwipeState()) {
mSwipeSharedState.dump(" ", pw);
sSwipeSharedState.dump(" ", pw);
}
pw.println(" mConsumer=" + mConsumer.getName());
pw.println("FeatureFlags:");

View File

@ -39,7 +39,7 @@ public class ResetGestureInputConsumer implements InputConsumer {
public void onMotionEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN
&& mSwipeSharedState.getActiveListener() != null) {
mSwipeSharedState.clearAllState();
mSwipeSharedState.clearAllState(false /* finishAnimation */);
}
}
}

View File

@ -106,6 +106,10 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet {
finishController(false /* toRecents */, null, false /* sendUserLeaveHint */);
}
public void finishAnimation() {
finishController(true /* toRecents */, null, false /* sendUserLeaveHint */);
}
public interface SwipeAnimationListener {
void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet);

View File

@ -765,7 +765,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
LauncherAnimationRunner.AnimationResult result) {
if (!mLauncher.hasBeenResumed()) {
// If launcher is not resumed, wait until new async-frame after resume
mLauncher.setOnResumeCallback(() ->
mLauncher.addOnResumeCallback(() ->
postAsyncCallback(mHandler, () ->
onCreateAnimation(targetCompats, result)));
return;

View File

@ -244,7 +244,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Thunk boolean mWorkspaceLoading = true;
private OnResumeCallback mOnResumeCallback;
private ArrayList<OnResumeCallback> mOnResumeCallbacks = new ArrayList<>();
private ViewOnDrawExecutor mPendingExecutor;
@ -869,6 +869,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Override
protected void onStop() {
super.onStop();
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onStop();
}
@ -951,7 +952,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mHandler.removeCallbacks(mHandleDeferredResume);
Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
setOnResumeCallback(null);
for (OnResumeCallback cb : mOnResumeCallbacks) {
cb.onLauncherResume();
}
mOnResumeCallbacks.clear();
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
@ -1805,6 +1809,16 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
android.util.Log.d(TestProtocol.NO_START_TAG,
"startActivitySafely outer");
}
if (!hasBeenResumed()) {
// Workaround an issue where the WM launch animation is clobbered when finishing the
// recents animation into launcher. Defer launching the activity until Launcher is
// next resumed.
addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));
UiFactory.clearSwipeSharedState(true /* finishAnimation */);
return true;
}
boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
if (success && v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
@ -1813,7 +1827,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
// state when we return to launcher.
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
setOnResumeCallback(btv);
addOnResumeCallback(btv);
}
return success;
}
@ -1861,11 +1875,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return result;
}
public void setOnResumeCallback(OnResumeCallback callback) {
if (mOnResumeCallback != null) {
mOnResumeCallback.onLauncherResume();
}
mOnResumeCallback = callback;
public void addOnResumeCallback(OnResumeCallback callback) {
mOnResumeCallbacks.add(callback);
}
/**

View File

@ -179,7 +179,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
DeferredOnComplete deferred = (DeferredOnComplete) d.dragSource;
if (target != null) {
deferred.mPackageName = target.getPackageName();
mLauncher.setOnResumeCallback(deferred);
mLauncher.addOnResumeCallback(deferred);
} else {
deferred.sendFailure();
}

View File

@ -93,4 +93,6 @@ public class UiFactory {
public static void resetPendingActivityResults(Launcher launcher, int requestCode) { }
public static void clearSwipeSharedState(boolean finishAnimation) {}
}