Merge "Consolidate recent animation in split screen with shell-transition"

This commit is contained in:
Jerry Chang
2022-01-19 01:45:56 +00:00
committed by Android (Google) Code Review
4 changed files with 88 additions and 48 deletions

View File

@@ -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() {

View File

@@ -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();

View File

@@ -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

View File

@@ -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()]);
}