diff options
3 files changed, 99 insertions, 47 deletions
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 2bd49bfa6219..a4d15e07a3ed 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.RemoteAnimationTarget.MODE_OPENING; +import static android.view.View.FOCUS_FORWARD; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_NONE; @@ -60,6 +61,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.TransitionAnimation; import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.utils.InsetUtils; +import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.ArrayList; @@ -167,6 +169,24 @@ class BackNavigationController { return null; } + // Move focus to the adjacent embedded window if it is higher than this window + final TaskFragment taskFragment = window.getTaskFragment(); + final TaskFragment adjacentTaskFragment = + taskFragment != null ? taskFragment.getAdjacentTaskFragment() : null; + if (adjacentTaskFragment != null && taskFragment.isEmbedded() + && Flags.embeddedActivityBackNavFlag()) { + final WindowContainer parent = taskFragment.getParent(); + if (parent.mChildren.indexOf(taskFragment) < parent.mChildren.indexOf( + adjacentTaskFragment)) { + mWindowManagerService.moveFocusToAdjacentWindow(window, FOCUS_FORWARD); + window = wmService.getFocusedWindowLocked(); + if (window == null) { + Slog.e(TAG, "Adjacent window is null, returning null."); + return null; + } + } + } + // This is needed to bridge the old and new back behavior with recents. While in // Overview with live tile enabled, the previous app is technically focused but we // add an input consumer to capture all input that would otherwise go to the apps diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f8ac8da710c8..9650b8bc2281 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -9156,55 +9156,63 @@ public class WindowManagerService extends IWindowManager.Stub if (fromWin == null || !fromWin.isFocused()) { return false; } - final TaskFragment fromFragment = fromWin.getTaskFragment(); - if (fromFragment == null) { - return false; - } - final TaskFragment adjacentFragment = fromFragment.getAdjacentTaskFragment(); - if (adjacentFragment == null || adjacentFragment.asTask() != null) { - // Don't move the focus to another task. - return false; - } - final Rect fromBounds = fromFragment.getBounds(); - final Rect adjacentBounds = adjacentFragment.getBounds(); - switch (direction) { - case View.FOCUS_LEFT: - if (adjacentBounds.left >= fromBounds.left) { - return false; - } - break; - case View.FOCUS_UP: - if (adjacentBounds.top >= fromBounds.top) { - return false; - } - break; - case View.FOCUS_RIGHT: - if (adjacentBounds.right <= fromBounds.right) { - return false; - } - break; - case View.FOCUS_DOWN: - if (adjacentBounds.bottom <= fromBounds.bottom) { - return false; - } - break; - case View.FOCUS_BACKWARD: - case View.FOCUS_FORWARD: - // These are not absolute directions. Skip checking the bounds. - break; - default: + return moveFocusToAdjacentWindow(fromWin, direction); + } + } + + boolean moveFocusToAdjacentWindow(WindowState fromWin, @FocusDirection int direction) { + final TaskFragment fromFragment = fromWin.getTaskFragment(); + if (fromFragment == null) { + return false; + } + final TaskFragment adjacentFragment = fromFragment.getAdjacentTaskFragment(); + if (adjacentFragment == null || adjacentFragment.asTask() != null) { + // Don't move the focus to another task. + return false; + } + if (adjacentFragment.isIsolatedNav()) { + // Don't move the focus if the adjacent TF is isolated navigation. + return false; + } + final Rect fromBounds = fromFragment.getBounds(); + final Rect adjacentBounds = adjacentFragment.getBounds(); + switch (direction) { + case View.FOCUS_LEFT: + if (adjacentBounds.left >= fromBounds.left) { return false; - } - final ActivityRecord topRunningActivity = adjacentFragment.topRunningActivity( - true /* focusableOnly */); - if (topRunningActivity == null) { - return false; - } - moveDisplayToTopInternal(topRunningActivity.getDisplayId()); - handleTaskFocusChange(topRunningActivity.getTask(), topRunningActivity); - if (fromWin.isFocused()) { + } + break; + case View.FOCUS_UP: + if (adjacentBounds.top >= fromBounds.top) { + return false; + } + break; + case View.FOCUS_RIGHT: + if (adjacentBounds.right <= fromBounds.right) { + return false; + } + break; + case View.FOCUS_DOWN: + if (adjacentBounds.bottom <= fromBounds.bottom) { + return false; + } + break; + case View.FOCUS_BACKWARD: + case View.FOCUS_FORWARD: + // These are not absolute directions. Skip checking the bounds. + break; + default: return false; - } + } + final ActivityRecord topRunningActivity = adjacentFragment.topRunningActivity( + true /* focusableOnly */); + if (topRunningActivity == null) { + return false; + } + moveDisplayToTopInternal(topRunningActivity.getDisplayId()); + handleTaskFocusChange(topRunningActivity.getTask(), topRunningActivity); + if (fromWin.isFocused()) { + return false; } return true; } 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 402cbccbca01..c44be7b9db51 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -56,6 +56,7 @@ import android.os.Bundle; import android.os.RemoteCallback; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; import android.util.ArraySet; import android.view.WindowManager; import android.window.BackAnimationAdapter; @@ -69,6 +70,7 @@ import android.window.TaskSnapshot; import android.window.WindowOnBackInvokedDispatcher; import com.android.server.LocalServices; +import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Test; @@ -81,6 +83,12 @@ import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +/** + * Tests for the {@link BackNavigationController} class. + * + * Build/Install/Run: + * atest WmTests:BackNavigationControllerTests + */ @Presubmit @RunWith(WindowTestRunner.class) public class BackNavigationControllerTests extends WindowTestsBase { @@ -623,6 +631,22 @@ public class BackNavigationControllerTests extends WindowTestsBase { 0, navigationObserver.getCount()); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_EMBEDDED_ACTIVITY_BACK_NAV_FLAG) + public void testAdjacentFocusInActivityEmbedding() { + Task task = createTask(mDefaultDisplay); + TaskFragment primary = createTaskFragmentWithActivity(task); + TaskFragment secondary = createTaskFragmentWithActivity(task); + primary.setAdjacentTaskFragment(secondary); + secondary.setAdjacentTaskFragment(primary); + + WindowState windowState = mock(WindowState.class); + doReturn(windowState).when(mWm).getFocusedWindowLocked(); + doReturn(primary).when(windowState).getTaskFragment(); + + startBackNavigation(); + verify(mWm).moveFocusToAdjacentWindow(any(), anyInt()); + } /** * Test with |