From 3a1619d68e829829848cf0c41fcf86e4671042d8 Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Fri, 7 Jul 2017 14:38:09 -0700 Subject: [PATCH] Position app with short aspect ratio opposite of nav bar When an application doesn't support tall aspect ratio of the screen where it's displayed, it should be positioned on the opposite side from navigation bar. It's supposed to create an effect of extended black nav bar. Bug: 62893418 Test: go/wm-smoke Test: ActivityRecordTests#testPositionLimitedAspectRatioNavBarBottom Test: ActivityRecordTests#testPositionLimitedAspectRatioNavBarLeft Test: ActivityRecordTests#testPositionLimitedAspectRatioNavBarRight Change-Id: I2cd3d236ee8d0cc263fee4c0a436d78c755eb9b7 --- core/java/android/view/WindowManagerPolicy.java | 13 ++++++++ .../java/com/android/server/am/ActivityRecord.java | 13 ++++++++ .../android/server/policy/PhoneWindowManager.java | 10 +++--- .../android/server/wm/WindowManagerService.java | 16 ++++++++++ .../com/android/server/am/ActivityRecordTests.java | 37 ++++++++++++++++++++++ .../com/android/server/am/ActivityTestsBase.java | 1 + .../android/server/wm/TestWindowManagerPolicy.java | 6 ++++ 7 files changed, 92 insertions(+), 4 deletions(-) diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 7538f6561c1e..ba9e05c2d870 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -150,6 +150,11 @@ public interface WindowManagerPolicy { public final static int PRESENCE_INTERNAL = 1 << 0; public final static int PRESENCE_EXTERNAL = 1 << 1; + // Navigation bar position values + int NAV_BAR_LEFT = 1 << 0; + int NAV_BAR_RIGHT = 1 << 1; + int NAV_BAR_BOTTOM = 1 << 2; + public final static boolean WATCH_POINTER = false; /** @@ -1676,6 +1681,14 @@ public interface WindowManagerPolicy { public boolean isNavBarForcedShownLw(WindowState win); /** + * @return The side of the screen where navigation bar is positioned. + * @see #NAV_BAR_LEFT + * @see #NAV_BAR_RIGHT + * @see #NAV_BAR_BOTTOM + */ + int getNavBarPosition(); + + /** * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system * bar or button bar. See {@link #getNonDecorDisplayWidth}. * diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 6a8f6d35c7c0..17f45ff2a9a0 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -74,6 +74,7 @@ import static android.os.Build.VERSION_CODES.HONEYCOMB; import static android.os.Build.VERSION_CODES.O; import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import static android.view.WindowManagerPolicy.NAV_BAR_LEFT; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE; @@ -154,6 +155,7 @@ import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IApplicationToken; import android.view.WindowManager.LayoutParams; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; import com.android.internal.util.XmlUtils; @@ -2358,6 +2360,17 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // Compute configuration based on max supported width and height. outBounds.set(0, 0, maxActivityWidth, maxActivityHeight); + // Position the activity frame on the opposite side of the nav bar. + final int navBarPosition = service.mWindowManager.getNavBarPosition(); + final int left = navBarPosition == NAV_BAR_LEFT + ? configuration.appBounds.right - outBounds.width() : 0; + outBounds.offsetTo(left, 0 /* top */); + } + + /** Get bounds of the activity. */ + @VisibleForTesting + Rect getBounds() { + return new Rect(mBounds); } /** diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 8425d235fe66..75fc25aaec77 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -358,10 +358,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER = "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver"; - private static final int NAV_BAR_BOTTOM = 0; - private static final int NAV_BAR_RIGHT = 1; - private static final int NAV_BAR_LEFT = 2; - /** * Keyguard stuff */ @@ -6943,6 +6939,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + public int getNavBarPosition() { + // TODO(multi-display): Support system decor on secondary displays. + return mNavigationBarPosition; + } + + @Override public boolean isDockSideAllowed(int dockSide) { // We do not allow all dock sides at which the navigation bar touches the docked stack. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ebfeac339083..1686075548dc 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6292,6 +6292,22 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** + * Used by ActivityManager to determine where to position an app with aspect ratio shorter then + * the screen is. + * @see WindowManagerPolicy#getNavBarPosition() + */ + public int getNavBarPosition() { + synchronized (mWindowMap) { + // Perform layout if it was scheduled before to make sure that we get correct nav bar + // position when doing rotations. + final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked(); + defaultDisplayContent.performLayout(false /* initial */, + false /* updateInputWindows */); + return mPolicy.getNavBarPosition(); + } + } + @Override public WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name, InputEventReceiver.Factory inputEventReceiverFactory) { diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java index f75d49cae574..2252c85dddf2 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -16,10 +16,15 @@ package com.android.server.am; +import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM; +import static android.view.WindowManagerPolicy.NAV_BAR_LEFT; +import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.when; import android.content.ComponentName; +import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; @@ -94,4 +99,36 @@ public class ActivityRecordTests extends ActivityTestsBase { return -1; } + + @Test + public void testPositionLimitedAspectRatioNavBarBottom() throws Exception { + verifyPositionWithLimitedAspectRatio(NAV_BAR_BOTTOM, new Rect(0, 0, 1000, 2000), 1.5f, + new Rect(0, 0, 1000, 1500)); + } + + @Test + public void testPositionLimitedAspectRatioNavBarLeft() throws Exception { + verifyPositionWithLimitedAspectRatio(NAV_BAR_LEFT, new Rect(0, 0, 2000, 1000), 1.5f, + new Rect(500, 0, 2000, 1000)); + } + + @Test + public void testPositionLimitedAspectRatioNavBarRight() throws Exception { + verifyPositionWithLimitedAspectRatio(NAV_BAR_RIGHT, new Rect(0, 0, 2000, 1000), 1.5f, + new Rect(0, 0, 1500, 1000)); + } + + private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds, + float aspectRatio, Rect expectedActivityBounds) { + final ActivityManagerService service = createActivityManagerService(); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); + final ActivityRecord record = createActivity(service, testActivityComponent, task); + + // Verify with nav bar on the right. + when(service.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition); + task.getConfiguration().setAppBounds(taskBounds); + record.info.maxAspectRatio = aspectRatio; + record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */); + assertEquals(expectedActivityBounds, record.getBounds()); + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index bac121695ed9..16bc011f97b5 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -120,6 +120,7 @@ public class ActivityTestsBase { null /*_taskDescription*/, new ActivityManager.TaskThumbnailInfo()); final ActivityStack stack = service.mStackSupervisor.getStack(stackId, true /*createStaticStackIfNeeded*/, true /*onTop*/); + service.mStackSupervisor.setFocusStackUnchecked("test", stack); stack.addTask(task, true, "creating test task"); task.setStack(stack); task.setWindowContainerController(mock(TaskWindowContainerController.class)); diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index a4e56fc9f745..0a7a5f26d35e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -614,6 +615,11 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override + public int getNavBarPosition() { + return NAV_BAR_BOTTOM; + } + + @Override public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight, Rect outInsets) { -- 2.11.0