Merge "Consolidate recent animation in split screen with shell-transition"
This commit is contained in:
@@ -44,6 +44,7 @@ import android.window.RemoteTransition;
|
||||
import android.window.TransitionInfo;
|
||||
import android.window.WindowContainerToken;
|
||||
import android.window.WindowContainerTransaction;
|
||||
import android.window.WindowContainerTransactionCallback;
|
||||
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
@@ -66,28 +67,26 @@ class SplitScreenTransitions {
|
||||
|
||||
DismissTransition mPendingDismiss = null;
|
||||
IBinder mPendingEnter = null;
|
||||
IBinder mPendingRecent = null;
|
||||
|
||||
private IBinder mAnimatingTransition = null;
|
||||
private OneShotRemoteHandler mRemoteHandler = null;
|
||||
|
||||
private Transitions.TransitionFinishCallback mRemoteFinishCB = (wct, wctCB) -> {
|
||||
if (wct != null || wctCB != null) {
|
||||
throw new UnsupportedOperationException("finish transactions not supported yet.");
|
||||
}
|
||||
onFinish();
|
||||
};
|
||||
private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
|
||||
|
||||
/** Keeps track of currently running animations */
|
||||
private final ArrayList<Animator> mAnimations = new ArrayList<>();
|
||||
private final StageCoordinator mStageCoordinator;
|
||||
|
||||
private Transitions.TransitionFinishCallback mFinishCallback = null;
|
||||
private SurfaceControl.Transaction mFinishTransaction;
|
||||
|
||||
SplitScreenTransitions(@NonNull TransactionPool pool, @NonNull Transitions transitions,
|
||||
@NonNull Runnable onFinishCallback) {
|
||||
@NonNull Runnable onFinishCallback, StageCoordinator stageCoordinator) {
|
||||
mTransactionPool = pool;
|
||||
mTransitions = transitions;
|
||||
mOnFinish = onFinishCallback;
|
||||
mStageCoordinator = stageCoordinator;
|
||||
}
|
||||
|
||||
void playAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
|
||||
@@ -166,7 +165,7 @@ class SplitScreenTransitions {
|
||||
}
|
||||
}
|
||||
t.apply();
|
||||
onFinish();
|
||||
onFinish(null /* wct */, null /* wctCB */);
|
||||
}
|
||||
|
||||
/** Starts a transition to enter split with a remote transition animator. */
|
||||
@@ -203,7 +202,26 @@ class SplitScreenTransitions {
|
||||
return transition;
|
||||
}
|
||||
|
||||
void onFinish() {
|
||||
IBinder startRecentTransition(@Nullable IBinder transition, WindowContainerTransaction wct,
|
||||
Transitions.TransitionHandler handler, @Nullable RemoteTransition remoteTransition) {
|
||||
if (transition == null) {
|
||||
transition = mTransitions.startTransition(TRANSIT_OPEN, wct, handler);
|
||||
}
|
||||
mPendingRecent = transition;
|
||||
|
||||
if (remoteTransition != null) {
|
||||
// Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
|
||||
mRemoteHandler = new OneShotRemoteHandler(
|
||||
mTransitions.getMainExecutor(), remoteTransition);
|
||||
mRemoteHandler.setTransition(transition);
|
||||
}
|
||||
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
|
||||
+ " deduced Enter recent panel");
|
||||
return transition;
|
||||
}
|
||||
|
||||
void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
|
||||
if (!mAnimations.isEmpty()) return;
|
||||
mOnFinish.run();
|
||||
if (mFinishTransaction != null) {
|
||||
@@ -211,14 +229,23 @@ class SplitScreenTransitions {
|
||||
mTransactionPool.release(mFinishTransaction);
|
||||
mFinishTransaction = null;
|
||||
}
|
||||
mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
|
||||
mFinishCallback = null;
|
||||
if (mFinishCallback != null) {
|
||||
mFinishCallback.onTransitionFinished(wct /* wct */, wctCB /* wctCB */);
|
||||
mFinishCallback = null;
|
||||
}
|
||||
if (mAnimatingTransition == mPendingEnter) {
|
||||
mPendingEnter = null;
|
||||
}
|
||||
if (mPendingDismiss != null && mPendingDismiss.mTransition == mAnimatingTransition) {
|
||||
mPendingDismiss = null;
|
||||
}
|
||||
if (mAnimatingTransition == mPendingRecent) {
|
||||
// If the wct is not null while finishing recent transition, it indicates it's not
|
||||
// returning to home and hence needing the wct to reorder tasks.
|
||||
final boolean toHome = wct == null;
|
||||
mStageCoordinator.finishRecentAnimation(toHome);
|
||||
mPendingRecent = null;
|
||||
}
|
||||
mAnimatingTransition = null;
|
||||
}
|
||||
|
||||
@@ -240,7 +267,7 @@ class SplitScreenTransitions {
|
||||
mTransactionPool.release(transaction);
|
||||
mTransitions.getMainExecutor().execute(() -> {
|
||||
mAnimations.remove(va);
|
||||
onFinish();
|
||||
onFinish(null /* wct */, null /* wctCB */);
|
||||
});
|
||||
};
|
||||
va.addListener(new Animator.AnimatorListener() {
|
||||
@@ -288,7 +315,7 @@ class SplitScreenTransitions {
|
||||
mTransactionPool.release(transaction);
|
||||
mTransitions.getMainExecutor().execute(() -> {
|
||||
mAnimations.remove(va);
|
||||
onFinish();
|
||||
onFinish(null /* wct */, null /* wctCB */);
|
||||
});
|
||||
};
|
||||
va.addListener(new AnimatorListenerAdapter() {
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
|
||||
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
|
||||
@@ -236,7 +237,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
deviceStateManager.registerCallback(taskOrganizer.getExecutor(),
|
||||
new DeviceStateManager.FoldStateListener(mContext, this::onFoldedStateChanged));
|
||||
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
|
||||
mOnTransitionAnimationComplete);
|
||||
mOnTransitionAnimationComplete, this);
|
||||
mDisplayController.addDisplayWindowListener(this);
|
||||
mDisplayLayout = new DisplayLayout(displayController.getDisplayLayout(displayId));
|
||||
transitions.addHandler(this);
|
||||
@@ -266,7 +267,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
mRootTDAOrganizer.registerListener(displayId, this);
|
||||
mSplitLayout = splitLayout;
|
||||
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
|
||||
mOnTransitionAnimationComplete);
|
||||
mOnTransitionAnimationComplete, this);
|
||||
mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
|
||||
mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
|
||||
mLogger = logger;
|
||||
@@ -1271,13 +1272,16 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
final int activityType = triggerTask.getActivityType();
|
||||
if (activityType == ACTIVITY_TYPE_ASSISTANT) {
|
||||
// We don't want assistant panel to dismiss split screen, so do nothing.
|
||||
} else if (activityType == ACTIVITY_TYPE_HOME
|
||||
|| activityType == ACTIVITY_TYPE_RECENTS) {
|
||||
// Enter overview panel, so start recent transition.
|
||||
mSplitTransitions.startRecentTransition(transition, out, this,
|
||||
request.getRemoteTransition());
|
||||
} else {
|
||||
// Going home or occluded by the other fullscreen task, so dismiss both.
|
||||
// Occluded by the other fullscreen task, so dismiss both.
|
||||
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
|
||||
final int exitReason = activityType == ACTIVITY_TYPE_HOME
|
||||
? EXIT_REASON_RETURN_HOME : EXIT_REASON_UNKNOWN;
|
||||
mSplitTransitions.startDismissTransition(transition, out, this,
|
||||
STAGE_TYPE_UNDEFINED, exitReason);
|
||||
STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1307,13 +1311,14 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
@NonNull SurfaceControl.Transaction startTransaction,
|
||||
@NonNull SurfaceControl.Transaction finishTransaction,
|
||||
@NonNull Transitions.TransitionFinishCallback finishCallback) {
|
||||
if (transition != mSplitTransitions.mPendingEnter && (
|
||||
mSplitTransitions.mPendingDismiss == null
|
||||
if (transition != mSplitTransitions.mPendingEnter
|
||||
&& transition != mSplitTransitions.mPendingRecent
|
||||
&& (mSplitTransitions.mPendingDismiss == null
|
||||
|| mSplitTransitions.mPendingDismiss.mTransition != transition)) {
|
||||
// Not entering or exiting, so just do some house-keeping and validation.
|
||||
|
||||
// If we're not in split-mode, just abort so something else can handle it.
|
||||
if (!isSplitScreenVisible()) return false;
|
||||
if (!mMainStage.isActive()) return false;
|
||||
|
||||
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
|
||||
final TransitionInfo.Change change = info.getChanges().get(iC);
|
||||
@@ -1356,6 +1361,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
boolean shouldAnimate = true;
|
||||
if (mSplitTransitions.mPendingEnter == transition) {
|
||||
shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
|
||||
} else if (mSplitTransitions.mPendingRecent == transition) {
|
||||
shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction);
|
||||
} else if (mSplitTransitions.mPendingDismiss != null
|
||||
&& mSplitTransitions.mPendingDismiss.mTransition == transition) {
|
||||
shouldAnimate = startPendingDismissAnimation(
|
||||
@@ -1500,6 +1507,23 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean startPendingRecentAnimation(@NonNull IBinder transition,
|
||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
|
||||
setDividerVisibility(false, t);
|
||||
return true;
|
||||
}
|
||||
|
||||
void finishRecentAnimation(boolean toHome) {
|
||||
if (toHome) {
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
|
||||
mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
|
||||
STAGE_TYPE_UNDEFINED, EXIT_REASON_RETURN_HOME);
|
||||
} else {
|
||||
setDividerVisibility(true, null /* t */);
|
||||
}
|
||||
}
|
||||
|
||||
private void addDividerBarToTransition(@NonNull TransitionInfo info,
|
||||
@NonNull SurfaceControl.Transaction t, boolean show) {
|
||||
final SurfaceControl leash = mSplitLayout.getDividerLeash();
|
||||
|
||||
@@ -251,7 +251,7 @@ public class SplitTransitionTests extends ShellTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissToHome() {
|
||||
public void testEnterRecents() {
|
||||
enterSplit();
|
||||
|
||||
ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder()
|
||||
@@ -264,7 +264,7 @@ public class SplitTransitionTests extends ShellTestCase {
|
||||
IBinder transition = mock(IBinder.class);
|
||||
WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request);
|
||||
|
||||
assertTrue(containsSplitExit(result));
|
||||
assertTrue(result.isEmpty());
|
||||
|
||||
// make sure we haven't made any local changes yet (need to wait until transition is ready)
|
||||
assertTrue(mStageCoordinator.isSplitScreenVisible());
|
||||
@@ -284,7 +284,7 @@ public class SplitTransitionTests extends ShellTestCase {
|
||||
mock(SurfaceControl.Transaction.class),
|
||||
mock(SurfaceControl.Transaction.class),
|
||||
mock(Transitions.TransitionFinishCallback.class));
|
||||
assertFalse(mStageCoordinator.isSplitScreenVisible());
|
||||
assertTrue(mStageCoordinator.isSplitScreenVisible());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.systemui.shared.system;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
|
||||
import static android.view.WindowManager.TRANSIT_CHANGE;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
||||
@@ -140,22 +139,11 @@ public class RemoteAnimationTargetCompat {
|
||||
// changes should be ordered top-to-bottom in z
|
||||
final int mode = change.getMode();
|
||||
|
||||
// Don't move anything that isn't independent within its parents
|
||||
if (!TransitionInfo.isIndependent(change, info)) {
|
||||
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
|
||||
t.show(leash);
|
||||
t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Launcher animates leaf tasks directly, so always reparent all task leashes to root leash.
|
||||
t.reparent(leash, info.getRootLeash());
|
||||
t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
|
||||
change.getStartAbsBounds().top - info.getRootOffset().y);
|
||||
|
||||
boolean hasParent = change.getParent() != null;
|
||||
|
||||
if (!hasParent) {
|
||||
t.reparent(leash, info.getRootLeash());
|
||||
t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
|
||||
change.getStartAbsBounds().top - info.getRootOffset().y);
|
||||
}
|
||||
t.show(leash);
|
||||
// Put all the OPEN/SHOW on top
|
||||
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
|
||||
@@ -266,14 +254,15 @@ public class RemoteAnimationTargetCompat {
|
||||
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
|
||||
final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
|
||||
for (int i = 0; i < info.getChanges().size(); i++) {
|
||||
boolean changeIsWallpaper =
|
||||
(info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
|
||||
final TransitionInfo.Change change = info.getChanges().get(i);
|
||||
final boolean changeIsWallpaper =
|
||||
(change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
|
||||
if (wallpapers != changeIsWallpaper) continue;
|
||||
out.add(new RemoteAnimationTargetCompat(info.getChanges().get(i),
|
||||
info.getChanges().size() - i, info, t));
|
||||
if (leashMap == null) continue;
|
||||
leashMap.put(info.getChanges().get(i).getLeash(),
|
||||
out.get(out.size() - 1).leash);
|
||||
|
||||
out.add(new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t));
|
||||
if (leashMap != null) {
|
||||
leashMap.put(change.getLeash(), out.get(out.size() - 1).leash);
|
||||
}
|
||||
}
|
||||
return out.toArray(new RemoteAnimationTargetCompat[out.size()]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user