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:
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user