Integrate keyguard behavior in split screen with shell-transition

Support to hide the divider bar when keyguard showing and support to
dismiss split after unlocked on folded device. Also unbind
show-when-locked split dismissing flow with stage visibility changed
callback to simplify the code.

Bug: 206487881
Test: atest WMShellUnitTests
Test: trigger split, won't see divider bar showing above keyguard.
Test: trigger split, fold the device and unlock will dismiss split. And
      there's no such split pair in recents.
Test: trigger split with show-when-locked activity, it'll dismiss split
      when it's occluding keyguard.
Change-Id: If536121ef0cae4acda12268ffb32024a9736bacd
This commit is contained in:
Jerry Chang
2021-12-14 14:13:58 +00:00
parent 52e1f36763
commit 7843221505
4 changed files with 61 additions and 94 deletions

View File

@@ -75,12 +75,6 @@ public interface SplitScreen {
return null;
}
/**
* Called when the keyguard occluded state changes.
* @param occluded Indicates if the keyguard is now occluded.
*/
void onKeyguardOccludedChanged(boolean occluded);
/**
* Called when the visibility of the keyguard changes.
* @param showing Indicates if the keyguard is now visible.
@@ -90,9 +84,6 @@ public interface SplitScreen {
/** Called when device waking up finished. */
void onFinishedWakingUp();
/** Called when device going to sleep finished. */
void onFinishedGoingToSleep();
/** Get a string representation of a stage type */
static String stageTypeToString(@StageType int stage) {
switch (stage) {

View File

@@ -249,10 +249,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
}
public void onKeyguardOccludedChanged(boolean occluded) {
mStageCoordinator.onKeyguardOccludedChanged(occluded);
}
public void onKeyguardVisibilityChanged(boolean showing) {
mStageCoordinator.onKeyguardVisibilityChanged(showing);
}
@@ -261,10 +257,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.onFinishedWakingUp();
}
public void onFinishedGoingToSleep() {
mStageCoordinator.onFinishedGoingToSleep();
}
public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
}
@@ -490,13 +482,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return mISplitScreen;
}
@Override
public void onKeyguardOccludedChanged(boolean occluded) {
mMainExecutor.execute(() -> {
SplitScreenController.this.onKeyguardOccludedChanged(occluded);
});
}
@Override
public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
if (mExecutors.containsKey(listener)) return;
@@ -538,13 +523,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
SplitScreenController.this.onFinishedWakingUp();
});
}
@Override
public void onFinishedGoingToSleep() {
mMainExecutor.execute(() -> {
SplitScreenController.this.onFinishedGoingToSleep();
});
}
}
/**

View File

@@ -46,7 +46,6 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
@@ -157,8 +156,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// and exit, since exit itself can trigger a number of changes that update the stages.
private boolean mShouldUpdateRecents;
private boolean mExitSplitScreenOnHide;
private boolean mKeyguardOccluded;
private boolean mDeviceSleep;
/** The target stage to dismiss to when unlock after folded. */
@StageType
@@ -171,6 +168,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// properly for the animation itself.
mSplitLayout.release();
mSplitLayout.resetDividerPosition();
mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
};
@@ -554,29 +552,54 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mTaskOrganizer.applyTransaction(wct);
}
void onKeyguardOccludedChanged(boolean occluded) {
// Do not exit split directly, because it needs to wait for task info update to determine
// which task should remain on top after split dismissed.
mKeyguardOccluded = occluded;
}
void onKeyguardVisibilityChanged(boolean showing) {
if (!showing && mMainStage.isActive()
&& mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
EXIT_REASON_DEVICE_FOLDED);
if (!mMainStage.isActive()) {
return;
}
if (ENABLE_SHELL_TRANSITIONS) {
// Update divider visibility so it won't float on top of keyguard.
setDividerVisibility(!showing, null /* transaction */);
}
if (!showing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
if (ENABLE_SHELL_TRANSITIONS) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
} else {
exitSplitScreen(
mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
EXIT_REASON_DEVICE_FOLDED);
}
}
}
void onFinishedWakingUp() {
if (mMainStage.isActive()) {
exitSplitScreenIfKeyguardOccluded();
if (!mMainStage.isActive()) {
return;
}
mDeviceSleep = false;
}
void onFinishedGoingToSleep() {
mDeviceSleep = true;
// Check if there's only one stage visible while keyguard occluded.
final boolean mainStageVisible = mMainStage.mRootTaskInfo.isVisible;
final boolean oneStageVisible =
mMainStage.mRootTaskInfo.isVisible != mSideStage.mRootTaskInfo.isVisible;
if (oneStageVisible) {
// Dismiss split because there's show-when-locked activity showing on top of keyguard.
// Also make sure the task contains show-when-locked activity remains on top after split
// dismissed.
if (!ENABLE_SHELL_TRANSITIONS) {
final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
} else {
final int dismissTop = mainStageVisible ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(dismissTop, wct);
mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
dismissTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
}
}
void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
@@ -607,19 +630,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
applyExitSplitScreen(childrenToTop, wct, exitReason);
}
private void exitSplitScreenIfKeyguardOccluded() {
final boolean mainStageVisible = mMainStageListener.mVisible;
final boolean oneStageVisible = mainStageVisible ^ mSideStageListener.mVisible;
if (mDeviceSleep && mKeyguardOccluded && oneStageVisible) {
// Only the stages include show-when-locked activity is visible while keyguard occluded.
// Dismiss split because there's show-when-locked activity showing on top of keyguard.
// Also make sure the task contains show-when-locked activity remains on top after split
// dismissed.
final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
}
private void applyExitSplitScreen(StageTaskListener childrenToTop,
WindowContainerTransaction wct, @ExitReason int exitReason) {
mRecentTasks.ifPresent(recentTasks -> {
@@ -669,6 +679,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
case EXIT_REASON_APP_FINISHED:
// One of the children enters PiP
case EXIT_REASON_CHILD_TASK_ENTER_PIP:
// One of the apps occludes lock screen.
case EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP:
// User has unlocked the device after folded
case EXIT_REASON_DEVICE_FOLDED:
return true;
default:
return false;
@@ -828,31 +842,27 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void onStageVisibilityChanged(StageListenerImpl stageListener) {
final boolean sideStageVisible = mSideStageListener.mVisible;
final boolean mainStageVisible = mMainStageListener.mVisible;
final boolean bothStageVisible = sideStageVisible && mainStageVisible;
final boolean bothStageInvisible = !sideStageVisible && !mainStageVisible;
final boolean sameVisibility = sideStageVisible == mainStageVisible;
if (bothStageInvisible) {
// Wait for both stages having the same visibility to prevent causing flicker.
if (mainStageVisible != sideStageVisible) {
return;
}
if (!mainStageVisible) {
// Both stages are not visible, check if it needs to dismiss split screen.
if (mExitSplitScreenOnHide
// Don't dismiss staged split when both stages are not visible due to sleeping
// display, like the cases keyguard showing or screen off.
// Don't dismiss split screen when both stages are not visible due to sleeping
// display.
|| (!mMainStage.mRootTaskInfo.isSleeping
&& !mSideStage.mRootTaskInfo.isSleeping)) {
// Don't dismiss staged split when both stages are not visible due to sleeping display,
// like the cases keyguard showing or screen off.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME);
}
}
exitSplitScreenIfKeyguardOccluded();
mSyncQueue.runInSync(t -> {
// Same above, we only set root tasks and divider leash visibility when both stage
// change to visible or invisible to avoid flicker.
if (sameVisibility) {
t.setVisibility(mSideStage.mRootLeash, bothStageVisible)
.setVisibility(mMainStage.mRootLeash, bothStageVisible);
setDividerVisibility(bothStageVisible, t);
}
t.setVisibility(mSideStage.mRootLeash, sideStageVisible)
.setVisibility(mMainStage.mRootLeash, mainStageVisible);
setDividerVisibility(mainStageVisible, t);
});
}
@@ -1374,11 +1384,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setSplitsVisible(false);
// Wait until after animation to update divider
if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
// Reset crops so they don't interfere with subsequent launches
t.setWindowCrop(mMainStage.mRootLeash, null);
t.setWindowCrop(mSideStage.mRootLeash, null);
}
// Reset crops so they don't interfere with subsequent launches
t.setWindowCrop(mMainStage.mRootLeash, null);
t.setWindowCrop(mSideStage.mRootLeash, null);
if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
logExit(dismissTransition.mReason);

View File

@@ -258,11 +258,6 @@ public final class WMShell extends CoreStartable
public void onKeyguardVisibilityChanged(boolean showing) {
splitScreen.onKeyguardVisibilityChanged(showing);
}
@Override
public void onKeyguardOccludedChanged(boolean occluded) {
splitScreen.onKeyguardOccludedChanged(occluded);
}
};
mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
@@ -271,11 +266,6 @@ public final class WMShell extends CoreStartable
public void onFinishedWakingUp() {
splitScreen.onFinishedWakingUp();
}
@Override
public void onFinishedGoingToSleep() {
splitScreen.onFinishedGoingToSleep();
}
});
}