Merge "Handle split screen accordingly after recent transition finished" into tm-qpr-dev am: c03b26dfed

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18347482

Change-Id: Ic4f64d94ecdcb26e143336db99e3841d6169272d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Jerry Chang
2022-06-02 00:49:27 +00:00
committed by Automerger Merge Worker
3 changed files with 69 additions and 69 deletions

View File

@@ -68,6 +68,7 @@ class SplitScreenTransitions {
private IBinder mAnimatingTransition = null; private IBinder mAnimatingTransition = null;
OneShotRemoteHandler mPendingRemoteHandler = null; OneShotRemoteHandler mPendingRemoteHandler = null;
private OneShotRemoteHandler mActiveRemoteHandler = null; private OneShotRemoteHandler mActiveRemoteHandler = null;
private boolean mEnterTransitionMerged;
private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish; private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
@@ -229,6 +230,18 @@ class SplitScreenTransitions {
} }
} }
void onTransitionMerged(@NonNull IBinder transition) {
// Once a pending enter transition got merged, make sure to append the reset of finishing
// operations to the finish transition.
if (transition == mPendingEnter) {
mFinishTransaction = mTransactionPool.acquire();
mStageCoordinator.finishEnterSplitScreen(mFinishTransaction);
mPendingEnter = null;
mPendingRemoteHandler = null;
mEnterTransitionMerged = true;
}
}
void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) { void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
if (!mAnimations.isEmpty()) return; if (!mAnimations.isEmpty()) return;
if (mAnimatingTransition == mPendingEnter) { if (mAnimatingTransition == mPendingEnter) {
@@ -238,18 +251,16 @@ class SplitScreenTransitions {
mPendingDismiss = null; mPendingDismiss = null;
} }
if (mAnimatingTransition == mPendingRecent) { if (mAnimatingTransition == mPendingRecent) {
// If the clean-up wct is null when finishing recent transition, it indicates it's if (!mEnterTransitionMerged) {
// returning to home and thus no need to reorder tasks. if (wct == null) wct = new WindowContainerTransaction();
final boolean returnToHome = wct == null; mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction);
if (returnToHome) {
wct = new WindowContainerTransaction();
} }
mStageCoordinator.onRecentTransitionFinished(returnToHome, wct, mFinishTransaction);
mPendingRecent = null; mPendingRecent = null;
} }
mPendingRemoteHandler = null; mPendingRemoteHandler = null;
mActiveRemoteHandler = null; mActiveRemoteHandler = null;
mAnimatingTransition = null; mAnimatingTransition = null;
mEnterTransitionMerged = false;
mOnFinish.run(); mOnFinish.run();
if (mFinishTransaction != null) { if (mFinishTransaction != null) {

View File

@@ -30,6 +30,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString; import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM; import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER; import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -369,10 +370,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
sideOptions = sideOptions != null ? sideOptions : new Bundle(); sideOptions = sideOptions != null ? sideOptions : new Bundle();
setSideStagePosition(sidePosition, wct); setSideStagePosition(sidePosition, wct);
if (mMainStage.isActive()) {
mMainStage.evictAllChildren(wct);
mSideStage.evictAllChildren(wct);
} else {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
mMainStage.activate(wct, false /* reparent */);
}
mSplitLayout.setDivideRatio(splitRatio); mSplitLayout.setDivideRatio(splitRatio);
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
mMainStage.activate(wct, false /* reparent */);
updateWindowBounds(mSplitLayout, wct); updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true); wct.reorder(mRootTaskInfo.token, true);
@@ -1507,16 +1513,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override @Override
public void onTransitionMerged(@NonNull IBinder transition) { public void onTransitionMerged(@NonNull IBinder transition) {
// Once the pending enter transition got merged, make sure to bring divider bar visible and mSplitTransitions.onTransitionMerged(transition);
// clear the pending transition from cache to prevent mess-up the following state.
if (transition == mSplitTransitions.mPendingEnter) {
final SurfaceControl.Transaction t = mTransactionPool.acquire();
finishEnterSplitScreen(t);
mSplitTransitions.mPendingEnter = null;
mSplitTransitions.mPendingRemoteHandler = null;
t.apply();
mTransactionPool.release(t);
}
} }
@Override @Override
@@ -1748,26 +1745,26 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return true; return true;
} }
void onRecentTransitionFinished(boolean returnToHome, WindowContainerTransaction wct, void onRecentTransitionFinished(WindowContainerTransaction wct,
SurfaceControl.Transaction finishT) { SurfaceControl.Transaction finishT) {
// Exclude the case that the split screen has been dismissed already. // Check if the recent transition is finished by returning to the current split so we can
if (!mMainStage.isActive()) { // restore the divider bar.
// The latest split dismissing transition might be a no-op transition and thus won't for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
// callback startAnimation, update split visibility here to cover this kind of no-op final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
// transition case. final IBinder container = op.getContainer();
setSplitsVisible(false); if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
return; && (mMainStage.containsContainer(container)
|| mSideStage.containsContainer(container))) {
setDividerVisibility(true, finishT);
return;
}
} }
if (returnToHome) { // Dismiss the split screen is it's not returning to split.
// When returning to home from recent apps, the splitting tasks are already hidden, so prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
// append the reset of dismissing operations into the clean-up wct. setSplitsVisible(false);
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct); setDividerVisibility(false, finishT);
setSplitsVisible(false); logExit(EXIT_REASON_UNKNOWN);
logExit(EXIT_REASON_RETURN_HOME);
} else {
setDividerVisibility(true, finishT);
}
} }
private void addDividerBarToTransition(@NonNull TransitionInfo info, private void addDividerBarToTransition(@NonNull TransitionInfo info,

View File

@@ -31,6 +31,7 @@ import android.app.ActivityManager;
import android.content.Context; import android.content.Context;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.IBinder;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.view.SurfaceSession; import android.view.SurfaceSession;
@@ -47,6 +48,7 @@ import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.splitscreen.SplitScreen.StageType; import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.function.Predicate;
/** /**
* Base class that handle common task org. related for split-screen stages. * Base class that handle common task org. related for split-screen stages.
@@ -119,63 +121,53 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
} }
boolean containsToken(WindowContainerToken token) { boolean containsToken(WindowContainerToken token) {
if (token.equals(mRootTaskInfo.token)) { return contains(t -> t.token.equals(token));
return true; }
}
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { boolean containsContainer(IBinder binder) {
if (token.equals(mChildrenTaskInfo.valueAt(i).token)) { return contains(t -> t.token.asBinder() == binder);
return true;
}
}
return false;
} }
/** /**
* Returns the top visible child task's id. * Returns the top visible child task's id.
*/ */
int getTopVisibleChildTaskId() { int getTopVisibleChildTaskId() {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible);
final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i); return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID;
if (info.isVisible) {
return info.taskId;
}
}
return INVALID_TASK_ID;
} }
/** /**
* Returns the top activity uid for the top child task. * Returns the top activity uid for the top child task.
*/ */
int getTopChildTaskUid() { int getTopChildTaskUid() {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo taskInfo =
final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i); getChildTaskInfo(t -> t.topActivityInfo != null);
if (info.topActivityInfo == null) { return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0;
continue;
}
return info.topActivityInfo.applicationInfo.uid;
}
return 0;
} }
/** @return {@code true} if this listener contains the currently focused task. */ /** @return {@code true} if this listener contains the currently focused task. */
boolean isFocused() { boolean isFocused() {
if (mRootTaskInfo == null) { return contains(t -> t.isFocused);
return false; }
}
if (mRootTaskInfo.isFocused) { private boolean contains(Predicate<ActivityManager.RunningTaskInfo> predicate) {
if (mRootTaskInfo != null && predicate.test(mRootTaskInfo)) {
return true; return true;
} }
return getChildTaskInfo(predicate) != null;
}
@Nullable
private ActivityManager.RunningTaskInfo getChildTaskInfo(
Predicate<ActivityManager.RunningTaskInfo> predicate) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
if (mChildrenTaskInfo.valueAt(i).isFocused) { final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
return true; if (predicate.test(taskInfo)) {
return taskInfo;
} }
} }
return null;
return false;
} }
@Override @Override