diff options
| -rw-r--r-- | services/core/java/com/android/server/wm/BackNavigationController.java | 37 | ||||
| -rw-r--r-- | services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java | 72 |
2 files changed, 84 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index b16602e0e475..14131e693561 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -235,6 +235,7 @@ class BackNavigationController { // We don't have an application callback, let's find the destination of the back gesture // The search logic should align with ActivityClientController#finishActivity prevActivity = currentTask.topRunningActivity(currentActivity.token, INVALID_TASK_ID); + final boolean isOccluded = isKeyguardOccluded(window); // TODO Dialog window does not need to attach on activity, check // window.mAttrs.type != TYPE_BASE_APPLICATION if ((window.getParent().getChildCount() > 1 @@ -244,16 +245,24 @@ class BackNavigationController { backType = BackNavigationInfo.TYPE_DIALOG_CLOSE; removedWindowContainer = window; } else if (prevActivity != null) { - // We have another Activity in the same currentTask to go to - backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY; - removedWindowContainer = currentActivity; - prevTask = prevActivity.getTask(); + if (!isOccluded || prevActivity.canShowWhenLocked()) { + // We have another Activity in the same currentTask to go to + backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY; + removedWindowContainer = currentActivity; + prevTask = prevActivity.getTask(); + } else { + backType = BackNavigationInfo.TYPE_CALLBACK; + } } else if (currentTask.returnsToHomeRootTask()) { - // Our Task should bring back to home - removedWindowContainer = currentTask; - prevTask = currentTask.getDisplayArea().getRootHomeTask(); - backType = BackNavigationInfo.TYPE_RETURN_TO_HOME; - mShowWallpaper = true; + if (isOccluded) { + backType = BackNavigationInfo.TYPE_CALLBACK; + } else { + // Our Task should bring back to home + removedWindowContainer = currentTask; + prevTask = currentTask.getDisplayArea().getRootHomeTask(); + backType = BackNavigationInfo.TYPE_RETURN_TO_HOME; + mShowWallpaper = true; + } } else if (currentActivity.isRootOfTask()) { // TODO(208789724): Create single source of truth for this, maybe in // RootWindowContainer @@ -267,7 +276,9 @@ class BackNavigationController { backType = BackNavigationInfo.TYPE_CALLBACK; } else { prevActivity = prevTask.getTopNonFinishingActivity(); - if (prevTask.isActivityTypeHome()) { + if (prevActivity == null || (isOccluded && !prevActivity.canShowWhenLocked())) { + backType = BackNavigationInfo.TYPE_CALLBACK; + } else if (prevTask.isActivityTypeHome()) { backType = BackNavigationInfo.TYPE_RETURN_TO_HOME; mShowWallpaper = true; } else { @@ -323,6 +334,12 @@ class BackNavigationController { return mAnimationTargets.mComposed && mAnimationTargets.mWaitTransition; } + boolean isKeyguardOccluded(WindowState focusWindow) { + final KeyguardController kc = mWindowManagerService.mAtmService.mKeyguardController; + final int displayId = focusWindow.getDisplayId(); + return kc.isKeyguardLocked(displayId) && kc.isDisplayOccluded(displayId); + } + // For legacy transition. /** * Once we find the transition targets match back animation targets, remove the target from diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index 3bce860b8720..1b77c95358ad 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -20,24 +20,23 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.window.BackNavigationInfo.typeToString; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; + import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.HardwareBuffer; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.view.WindowManager; @@ -48,7 +47,6 @@ import android.window.IOnBackInvokedCallback; import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedCallbackInfo; import android.window.OnBackInvokedDispatcher; -import android.window.TaskSnapshot; import android.window.WindowOnBackInvokedDispatcher; import com.android.server.LocalServices; @@ -67,6 +65,7 @@ public class BackNavigationControllerTests extends WindowTestsBase { private BackNavigationController mBackNavigationController; private WindowManagerInternal mWindowManagerInternal; private BackAnimationAdapter mBackAnimationAdapter; + private Task mRootHomeTask; @Before public void setUp() throws Exception { @@ -76,6 +75,7 @@ public class BackNavigationControllerTests extends WindowTestsBase { LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal); mBackNavigationController.setWindowManager(mWm); mBackAnimationAdapter = mock(BackAnimationAdapter.class); + mRootHomeTask = initHomeActivity(); } @Test @@ -101,7 +101,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { ActivityRecord recordA = createActivityRecord(taskA); Mockito.doNothing().when(recordA).reparentSurfaceControl(any(), any()); - withSystemCallback(createTopTaskWithActivity()); + final Task topTask = createTopTaskWithActivity(); + withSystemCallback(topTask); BackNavigationInfo backNavigationInfo = startBackNavigation(); assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull(); assertThat(typeToString(backNavigationInfo.getType())) @@ -111,6 +112,20 @@ public class BackNavigationControllerTests extends WindowTestsBase { verify(mBackNavigationController).scheduleAnimationLocked( eq(BackNavigationInfo.TYPE_CROSS_TASK), any(), eq(mBackAnimationAdapter), any()); + + // reset drawning status + topTask.forAllWindows(w -> { + makeWindowVisibleAndDrawn(w); + }, true); + setupKeyguardOccluded(); + backNavigationInfo = startBackNavigation(); + assertThat(typeToString(backNavigationInfo.getType())) + .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); + + doReturn(true).when(recordA).canShowWhenLocked(); + backNavigationInfo = startBackNavigation(); + assertThat(typeToString(backNavigationInfo.getType())) + .isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_TASK)); } @Test @@ -137,6 +152,20 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_ACTIVITY)); + + // reset drawing status + testCase.recordFront.forAllWindows(w -> { + makeWindowVisibleAndDrawn(w); + }, true); + setupKeyguardOccluded(); + backNavigationInfo = startBackNavigation(); + assertThat(typeToString(backNavigationInfo.getType())) + .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); + + doReturn(true).when(testCase.recordBack).canShowWhenLocked(); + backNavigationInfo = startBackNavigation(); + assertThat(typeToString(backNavigationInfo.getType())) + .isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_ACTIVITY)); } @Test @@ -164,12 +193,17 @@ public class BackNavigationControllerTests extends WindowTestsBase { @Test public void preparesForBackToHome() { - Task task = createTopTaskWithActivity(); - withSystemCallback(task); + final Task topTask = createTopTaskWithActivity(); + withSystemCallback(topTask); BackNavigationInfo backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME)); + + setupKeyguardOccluded(); + backNavigationInfo = startBackNavigation(); + assertThat(typeToString(backNavigationInfo.getType())) + .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); } @Test @@ -302,14 +336,22 @@ public class BackNavigationControllerTests extends WindowTestsBase { }; } - @NonNull - private TaskSnapshotController createMockTaskSnapshotController() { - TaskSnapshotController taskSnapshotController = mock(TaskSnapshotController.class); - TaskSnapshot taskSnapshot = mock(TaskSnapshot.class); - when(taskSnapshot.getHardwareBuffer()).thenReturn(mock(HardwareBuffer.class)); - when(taskSnapshotController.getSnapshot(anyInt(), anyInt(), anyBoolean(), anyBoolean())) - .thenReturn(taskSnapshot); - return taskSnapshotController; + private Task initHomeActivity() { + final Task task = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask(); + task.forAllLeafTasks((t) -> { + if (t.getTopMostActivity() == null) { + final ActivityRecord r = createActivityRecord(t); + Mockito.doNothing().when(t).reparentSurfaceControl(any(), any()); + Mockito.doNothing().when(r).reparentSurfaceControl(any(), any()); + } + }, true); + return task; + } + + private void setupKeyguardOccluded() { + final KeyguardController kc = mRootHomeTask.mTaskSupervisor.getKeyguardController(); + doReturn(true).when(kc).isKeyguardLocked(anyInt()); + doReturn(true).when(kc).isDisplayOccluded(anyInt()); } @NonNull |