From a75783bec4e9b20e6549faf6f53a852176811782 Mon Sep 17 00:00:00 2001 From: Mariia Sandrikova Date: Tue, 31 Aug 2021 22:34:25 +0100 Subject: [PATCH 1/2] [1/n] Letterbox Reachability: Repositioning on double tap. This is the first CL for ensuring reachability of letterboxed portrait-only apps in fullscreen landscape device orientation. The next CLs will add animation, restrict aspect ratio to split screen window size and add educational hints for the gesture. Current CL allows to customize left and right positions of the letterboxed windows and initially opens the app on the right side of the screen. Bug: 197549949 Test: atest WmTests:SizeCompatTests manual with adb shell cmd window set-letterbox-style --isReachabilityEnabled true Change-Id: I5a4f65510019c0dfc2b7d61efe0847d943467443 --- core/res/res/values/config.xml | 15 +++ core/res/res/values/symbols.xml | 2 + .../com/android/server/wm/ActivityRecord.java | 16 ++- .../java/com/android/server/wm/Letterbox.java | 60 +++++++--- .../server/wm/LetterboxConfiguration.java | 113 +++++++++++++++++- .../server/wm/LetterboxUiController.java | 54 ++++++++- .../server/wm/WindowManagerShellCommand.java | 76 +++++++++++- .../com/android/server/wm/LetterboxTest.java | 3 +- .../android/server/wm/SizeCompatTests.java | 4 + .../android/server/wm/WindowTestsBase.java | 13 +- 10 files changed, 321 insertions(+), 35 deletions(-) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 797ff867e00cb..d5f4cad699c5f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4873,6 +4873,21 @@ or > 1, it is ignored and central positionis used (0.5). --> 0.5 + + false + + + + 0.9 + + false diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ec0e02b150eb4..68563e2e59742 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4253,6 +4253,8 @@ + + diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 623bf931929ee..c4884ae894b06 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7534,11 +7534,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A parentAppBounds.width(), screenResolvedBounds.width()); } else { float positionMultiplier = - mWmService.mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(); - positionMultiplier = - (positionMultiplier < 0.0f || positionMultiplier > 1.0f) - // Default to central position if invalid value is provided. - ? 0.5f : positionMultiplier; + mLetterboxUiController.getHorizontalPositionMultiplier(newParentConfiguration); offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width()) * positionMultiplier); } @@ -7555,6 +7551,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration); } + void recomputeConfiguration() { + onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration()); + } + + boolean isInTransition() { + return mAtmService.getTransitionController().inTransition() // Shell transitions. + || isAnimating(PARENTS | TRANSITION); // Legacy transitions. + } + /** * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed * orientation then aspect ratio restrictions are also already respected. @@ -7657,6 +7662,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If the activity requires a different orientation (either by override or activityInfo), // make it fit the available bounds by scaling down its bounds. final int forcedOrientation = getRequestedConfigurationOrientation(); + if (forcedOrientation == ORIENTATION_UNDEFINED || (forcedOrientation == parentOrientation && orientationRespectedWithInsets)) { return; diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 5a249a5599bbb..c18c94d8242e8 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -19,14 +19,18 @@ package com.android.server.wm; import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; import static android.view.SurfaceControl.HIDDEN; +import android.content.Context; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.os.Process; +import android.view.GestureDetector; import android.view.InputChannel; +import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.InputWindowHandle; +import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.WindowManager; @@ -65,6 +69,8 @@ public class Letterbox { // for overlaping an app window and letterbox surfaces. private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow"); private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom }; + // Reachability gestures. + private final Runnable mDoubleTapCallback; /** * Constructs a Letterbox. @@ -77,7 +83,8 @@ public class Letterbox { Supplier colorSupplier, Supplier hasWallpaperBackgroundSupplier, Supplier blurRadiusSupplier, - Supplier darkScrimAlphaSupplier) { + Supplier darkScrimAlphaSupplier, + Runnable doubleTapCallback) { mSurfaceControlFactory = surfaceControlFactory; mTransactionFactory = transactionFactory; mAreCornersRounded = areCornersRounded; @@ -85,6 +92,7 @@ public class Letterbox { mHasWallpaperBackgroundSupplier = hasWallpaperBackgroundSupplier; mBlurRadiusSupplier = blurRadiusSupplier; mDarkScrimAlphaSupplier = darkScrimAlphaSupplier; + mDoubleTapCallback = doubleTapCallback; } /** @@ -231,18 +239,48 @@ public class Letterbox { return mAreCornersRounded.get() || mHasWallpaperBackgroundSupplier.get(); } - private static class InputInterceptor { - final InputChannel mClientChannel; - final InputWindowHandle mWindowHandle; - final InputEventReceiver mInputEventReceiver; - final WindowManagerService mWmService; - final IBinder mToken; + private final class TapEventReceiver extends InputEventReceiver { + + private final GestureDetector mDoubleTapDetector; + private final DoubleTapListener mDoubleTapListener; + + TapEventReceiver(InputChannel inputChannel, Context context) { + super(inputChannel, UiThread.getHandler().getLooper()); + mDoubleTapListener = new DoubleTapListener(); + mDoubleTapDetector = new GestureDetector(context, mDoubleTapListener); + } + + @Override + public void onInputEvent(InputEvent event) { + final MotionEvent motionEvent = (MotionEvent) event; + finishInputEvent(event, mDoubleTapDetector.onTouchEvent(motionEvent)); + } + } + + private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener { + @Override + public boolean onDoubleTapEvent(MotionEvent e) { + if (e.getAction() == MotionEvent.ACTION_UP) { + mDoubleTapCallback.run(); + return true; + } + return false; + } + } + + private final class InputInterceptor { + + private final InputChannel mClientChannel; + private final InputWindowHandle mWindowHandle; + private final InputEventReceiver mInputEventReceiver; + private final WindowManagerService mWmService; + private final IBinder mToken; InputInterceptor(String namePrefix, WindowState win) { mWmService = win.mWmService; final String name = namePrefix + (win.mActivityRecord != null ? win.mActivityRecord : win); mClientChannel = mWmService.mInputManager.createInputChannel(name); - mInputEventReceiver = new SimpleInputReceiver(mClientChannel); + mInputEventReceiver = new TapEventReceiver(mClientChannel, mWmService.mContext); mToken = mClientChannel.getToken(); @@ -280,12 +318,6 @@ public class Letterbox { mInputEventReceiver.dispose(); mClientChannel.dispose(); } - - private static class SimpleInputReceiver extends InputEventReceiver { - SimpleInputReceiver(InputChannel inputChannel) { - super(inputChannel, UiThread.getHandler().getLooper()); - } - } } private class LetterboxSurface { diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 34b834b3c6259..76a098d131fe4 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -85,6 +85,26 @@ final class LetterboxConfiguration { // side of the screen and 1.0 to the right side. private float mLetterboxHorizontalPositionMultiplier; + // Default horizontal position of a center of the letterboxed app window when reachability is + // enabled and an app is fullscreen in landscape device orientatio. 0 corresponds to the left + // side of the screen and 1.0 to the right side. + // It is used as a starting point for mLetterboxHorizontalMultiplierForReachability. + private float mDefaultPositionMultiplierForReachability; + + // Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape + // device orientation. + private boolean mIsReachabilityEnabled; + + // Horizontal position of a center of the letterboxed app window. 0 corresponds to + // the left side of the screen and 1 to the right side. Keep it global to prevent + // "jumps" when switching between letterboxed apps. It's updated to reposition the app + // window in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). + // Used in LetterboxUiController#getHorizontalPositionMultiplier which is called from + // ActivityRecord#updateResolvedBoundsHorizontalPosition. + // TODO(b/199426138): Global reachability setting causes a jump when resuming an app from + // Overview after changing position in another app. + private volatile float mLetterboxHorizontalMultiplierForReachability; + LetterboxConfiguration(Context systemUiContext) { mContext = systemUiContext; mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat( @@ -98,6 +118,11 @@ final class LetterboxConfiguration { R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha); mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat( R.dimen.config_letterboxHorizontalPositionMultiplier); + mIsReachabilityEnabled = mContext.getResources().getBoolean( + R.bool.config_letterboxIsReachabilityEnabled); + mDefaultPositionMultiplierForReachability = mContext.getResources().getFloat( + R.dimen.config_letterboxDefaultPositionMultiplierForReachability); + mLetterboxHorizontalMultiplierForReachability = mDefaultPositionMultiplierForReachability; } /** @@ -317,12 +342,12 @@ final class LetterboxConfiguration { * in {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} * or via an ADB command. 0 corresponds to the left side of the screen and 1 to the * right side. - * - *

This value can be outside of [0, 1] range so clients need to check and default to the - * central position (0.5). */ float getLetterboxHorizontalPositionMultiplier() { - return mLetterboxHorizontalPositionMultiplier; + return (mLetterboxHorizontalPositionMultiplier < 0.0f + || mLetterboxHorizontalPositionMultiplier > 1.0f) + // Default to central position if invalid value is provided. + ? 0.5f : mLetterboxHorizontalPositionMultiplier; } /** @@ -344,4 +369,84 @@ final class LetterboxConfiguration { com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier); } + /* + * Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape + * device orientation. + */ + boolean getIsReachabilityEnabled() { + return mIsReachabilityEnabled; + } + + /** + * Overrides whether reachability repositioning is allowed for letterboxed fullscreen apps in + * landscape device orientation. + */ + void setIsReachabilityEnabled(boolean enabled) { + mIsReachabilityEnabled = enabled; + } + + /** + * Resets whether reachability repositioning is allowed for letterboxed fullscreen apps in + * landscape device orientation to {@link R.bool.config_letterboxIsReachabilityEnabled}. + */ + void resetIsReachabilityEnabled() { + mIsReachabilityEnabled = mContext.getResources().getBoolean( + R.bool.config_letterboxIsReachabilityEnabled); + } + + /* + * Gets default horizontal position of a center of the letterboxed app window when reachability + * is enabled specified in {@link + * R.dimen.config_letterboxDefaultPositionMultiplierForReachability} or via an ADB command. + * 0 corresponds to the left side of the screen and 1 to the right side. The returned value is + * >= 0.0 and <= 1.0. + */ + float getDefaultPositionMultiplierForReachability() { + return (mDefaultPositionMultiplierForReachability < 0.0f + || mDefaultPositionMultiplierForReachability > 1.0f) + // Default to a right position if invalid value is provided. + ? 1.0f : mDefaultPositionMultiplierForReachability; + } + + /** + * Overrides default horizontal position of a center of the letterboxed app window when + * reachability is enabled. If given value < 0.0 or > 1.0, then it and a value of {@link + * R.dimen.config_letterboxDefaultPositionMultiplierForReachability} are ignored and the right + * position (1.0) is used. + */ + void setDefaultPositionMultiplierForReachability(float multiplier) { + mDefaultPositionMultiplierForReachability = multiplier; + } + + /** + * Resets default horizontal position of a center of the letterboxed app window when + * reachability is enabled to {@link + * R.dimen.config_letterboxDefaultPositionMultiplierForReachability}. + */ + void resetDefaultPositionMultiplierForReachability() { + mDefaultPositionMultiplierForReachability = mContext.getResources().getFloat( + R.dimen.config_letterboxDefaultPositionMultiplierForReachability); + } + + /* + * Gets horizontal position of a center of the letterboxed app window when reachability + * is enabled specified. 0 corresponds to the left side of the screen and 1 to the right side. + * + *

The position multiplier is changed to a symmetrical value computed as (1 - current + * multiplier) after each double tap in the letterbox area. + */ + float getHorizontalMultiplierForReachability() { + return mLetterboxHorizontalMultiplierForReachability; + } + + /** + * Changes horizontal position of a center of the letterboxed app window to the opposite + * (1 - current multiplier) when reachability is enabled specified. 0 corresponds to the left + * side of the screen and 1 to the right side. + */ + void flipHorizontalMultiplierForReachability() { + mLetterboxHorizontalMultiplierForReachability = + 1.0f - mLetterboxHorizontalMultiplierForReachability; + } + } diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index b6b8ad14e1060..c4c9d798bbc78 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; @@ -28,6 +31,7 @@ import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTy import android.annotation.Nullable; import android.app.ActivityManager.TaskDescription; +import android.content.res.Configuration; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; @@ -138,7 +142,8 @@ final class LetterboxUiController { this::getLetterboxBackgroundColor, this::hasWallpaperBackgroudForLetterbox, this::getLetterboxWallpaperBlurRadius, - this::getLetterboxWallpaperDarkScrimAlpha); + this::getLetterboxWallpaperDarkScrimAlpha, + this::handleDoubleTap); mLetterbox.attachInput(w); } mActivityRecord.getPosition(mTmpPoint); @@ -158,6 +163,49 @@ final class LetterboxUiController { } } + float getHorizontalPositionMultiplier(Configuration parentConfiguration) { + // Don't check resolved configuration because it may not be updated yet during + // configuration change. + return isReachabilityEnabled(parentConfiguration) + // Using the last global dynamic position to avoid "jumps" when moving + // between apps or activities. + ? mLetterboxConfiguration.getHorizontalMultiplierForReachability() + : mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(); + } + + private void handleDoubleTap() { + if (!isReachabilityEnabled() || mActivityRecord.isInTransition()) { + return; + } + + mLetterboxConfiguration.flipHorizontalMultiplierForReachability(); + + // TODO(197549949): Add animation for transition. + mActivityRecord.recomputeConfiguration(); + } + + /** + * Whether reachability is enabled for an activity in the curren configuration. + * + *

Conditions that needs to be met: + *

    + *
  • Activity is portrait-only. + *
  • Fullscreen window in landscape device orientation. + *
  • Reachability is enabled. + *
+ */ + private boolean isReachabilityEnabled(Configuration parentConfiguration) { + return mLetterboxConfiguration.getIsReachabilityEnabled() + && parentConfiguration.windowConfiguration.getWindowingMode() + == WINDOWING_MODE_FULLSCREEN + && parentConfiguration.orientation == ORIENTATION_LANDSCAPE + && mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT; + } + + private boolean isReachabilityEnabled() { + return isReachabilityEnabled(mActivityRecord.getParent().getConfiguration()); + } + @VisibleForTesting boolean shouldShowLetterboxUi(WindowState mainWindow) { return isSurfaceReadyAndVisible(mainWindow) && mainWindow.areAppWindowBoundsLetterboxed() @@ -308,8 +356,10 @@ final class LetterboxUiController { pw.println(prefix + " letterboxBackgroundWallpaperBlurRadius=" + getLetterboxWallpaperBlurRadius()); } + + pw.println(prefix + " isReachabilityEnabled=" + isReachabilityEnabled()); pw.println(prefix + " letterboxHorizontalPositionMultiplier=" - + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier()); + + getHorizontalPositionMultiplier(mActivityRecord.getParent().getConfiguration())); } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 1d1cb7031148a..47d7f030bcaab 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -745,7 +745,7 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } - private int runSeLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException { + private int runSetLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException { final float multiplier; try { String arg = getNextArgRequired(); @@ -764,6 +764,49 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } + private int runSetLetterboxIsReachabilityEnabled(PrintWriter pw) throws RemoteException { + String arg = getNextArg(); + final boolean enabled; + switch (arg) { + case "true": + case "1": + enabled = true; + break; + case "false": + case "0": + enabled = false; + break; + default: + getErrPrintWriter().println("Error: expected true, 1, false, 0, but got " + arg); + return -1; + } + + synchronized (mInternal.mGlobalLock) { + mLetterboxConfiguration.setIsReachabilityEnabled(enabled); + } + return 0; + } + + private int runSetLetterboxDefaultPositionMultiplierForReachability(PrintWriter pw) + throws RemoteException { + final float multiplier; + try { + String arg = getNextArgRequired(); + multiplier = Float.parseFloat(arg); + } catch (NumberFormatException e) { + getErrPrintWriter().println("Error: bad multiplier format " + e); + return -1; + } catch (IllegalArgumentException e) { + getErrPrintWriter().println( + "Error: multiplier should be provided as an argument " + e); + return -1; + } + synchronized (mInternal.mGlobalLock) { + mLetterboxConfiguration.setDefaultPositionMultiplierForReachability(multiplier); + } + return 0; + } + private int runSetLetterboxStyle(PrintWriter pw) throws RemoteException { if (peekNextArg() == null) { getErrPrintWriter().println("Error: No arguments provided."); @@ -793,7 +836,13 @@ public class WindowManagerShellCommand extends ShellCommand { runSetLetterboxBackgroundWallpaperDarkScrimAlpha(pw); break; case "--horizontalPositionMultiplier": - runSeLetterboxHorizontalPositionMultiplier(pw); + runSetLetterboxHorizontalPositionMultiplier(pw); + break; + case "--isReachabilityEnabled": + runSetLetterboxIsReachabilityEnabled(pw); + break; + case "--defaultPositionMultiplierReachability": + runSetLetterboxDefaultPositionMultiplierForReachability(pw); break; default: getErrPrintWriter().println( @@ -833,6 +882,12 @@ public class WindowManagerShellCommand extends ShellCommand { case "horizontalPositionMultiplier": mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier(); break; + case "isReachabilityEnabled": + mLetterboxConfiguration.getIsReachabilityEnabled(); + break; + case "defaultPositionMultiplierForReachability": + mLetterboxConfiguration.getDefaultPositionMultiplierForReachability(); + break; default: getErrPrintWriter().println( "Error: Unrecognized letterbox style option: " + arg); @@ -926,6 +981,8 @@ public class WindowManagerShellCommand extends ShellCommand { mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius(); mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha(); mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier(); + mLetterboxConfiguration.resetIsReachabilityEnabled(); + mLetterboxConfiguration.resetDefaultPositionMultiplierForReachability(); } } @@ -937,6 +994,10 @@ public class WindowManagerShellCommand extends ShellCommand { + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier()); pw.println("Aspect ratio: " + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio()); + pw.println("Is reachability enabled: " + + mLetterboxConfiguration.getIsReachabilityEnabled()); + pw.println("Default position multiplier for reachability: " + + mLetterboxConfiguration.getDefaultPositionMultiplierForReachability()); pw.println("Background type: " + LetterboxConfiguration.letterboxBackgroundTypeToString( @@ -1071,9 +1132,18 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" Horizontal position of app window center. If multiplier < 0 or > 1,"); pw.println(" both it and R.dimen.config_letterboxHorizontalPositionMultiplier"); pw.println(" are ignored and central position (0.5) is used."); + pw.println(" --isReachabilityEnabled [true|1|false|0]"); + pw.println(" Whether reachability repositioning is allowed for letterboxed"); + pw.println(" fullscreen apps in landscape device orientation."); + pw.println(" --defaultPositionMultiplierReachability multiplier"); + pw.println(" Default horizontal position of app window center when reachability is"); + pw.println(" enabled. If multiplier < 0.0 or > 1, both it and "); + pw.println(" R.dimen.config_letterboxDefaultPositionMultiplierForReachability"); + pw.println(" are ignored and right position (1.0) is used."); pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType"); pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha"); - pw.println(" |horizontalPositionMultiplier]"); + pw.println(" |horizontalPositionMultiplier|isReachabilityEnabled"); + pw.println(" |defaultPositionMultiplierForReachability]"); pw.println(" Resets overrides to default values for specified properties separated"); pw.println(" by space, e.g. 'reset-letterbox-style aspectRatio cornerRadius'."); pw.println(" If no arguments provided, all values will be reset."); diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java index 609d15937b2e2..78946fca7e8b8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -62,7 +62,8 @@ public class LetterboxTest { mSurfaces = new SurfaceControlMocker(); mLetterbox = new Letterbox(mSurfaces, StubTransaction::new, () -> mAreCornersRounded, () -> Color.valueOf(mColor), - () -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha); + () -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha, + /* doubleTapCallback= */ () -> {}); mTransaction = spy(StubTransaction.class); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 6407c92ee2aa8..348472a931497 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -1171,6 +1171,7 @@ public class SizeCompatTests extends WindowTestsBase { final WindowState w = addWindowToActivity(mActivity); // Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}. mActivity.mRootWindowContainer.performSurfacePlacement(); + mActivity.layoutLetterbox(null); // The letterbox insets should be [450, 0 - 250, 0]. assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0), mActivity.getLetterboxInsets()); @@ -1832,6 +1833,9 @@ public class SizeCompatTests extends WindowTestsBase { } private void assertLetterboxSurfacesDrawnBetweenActivityAndParentBounds(Rect parentBounds) { + // Ensure Letterbox is updated. + mActivity.layoutLetterbox(null); + // Letterbox should fill the gap between the parent bounds and the letterboxed activity. final Rect letterboxedBounds = new Rect(mActivity.getBounds()); assertTrue(parentBounds.contains(letterboxedBounds)); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 454ecd7e9d852..1f6065f014aef 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -223,6 +223,10 @@ class WindowTestsBase extends SystemServiceTestsBase { // {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}, // may be set on some device form factors. mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f); + // Ensure letterbox reachability treatment isn't overridden on any device target. + // {@link com.android.internal.R.bool.config_letterboxIsReachabilityEnabled}, + // may be set on some device form factors. + mAtm.mWindowManager.mLetterboxConfiguration.setIsReachabilityEnabled(false); checkDeviceSpecificOverridesNotApplied(); } @@ -230,12 +234,9 @@ class WindowTestsBase extends SystemServiceTestsBase { @After public void tearDown() throws Exception { // Revert back to device overrides. - mAtm.mWindowManager.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio( - mContext.getResources().getFloat( - com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio)); - mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( - mContext.getResources().getFloat( - com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier)); + mAtm.mWindowManager.mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio(); + mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier(); + mAtm.mWindowManager.mLetterboxConfiguration.resetIsReachabilityEnabled(); } /** From 9c293959301ffd176c04c66c7374bdebb732d259 Mon Sep 17 00:00:00 2001 From: Mariia Sandrikova Date: Wed, 1 Sep 2021 11:40:50 +0100 Subject: [PATCH 2/2] [2/n] Letterbox reachability: Aspect ratio as in split screen. Bug: 197549949 Test: atest WmTests:SizeCompatTests manual with adb shell cmd window set-letterbox-style --isReachabilityEnabled true Change-Id: Idb6b82f100ad67e446b8a36a5cc3325e49b1f914 --- .../com/android/server/wm/ActivityRecord.java | 4 +-- .../server/wm/LetterboxUiController.java | 33 ++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c4884ae894b06..2acf9c9aa410d 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7714,10 +7714,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final Rect prevResolvedBounds = new Rect(resolvedBounds); resolvedBounds.set(containingBounds); - // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with - // set-fixed-orientation-letterbox-aspect-ratio. final float letterboxAspectRatioOverride = - mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio(); + mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig); final float desiredAspectRatio = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds); diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index c4c9d798bbc78..0d99bacff33dd 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -21,6 +21,7 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; +import static com.android.server.wm.ActivityRecord.computeAspectRatio; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND; @@ -32,6 +33,7 @@ import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTy import android.annotation.Nullable; import android.app.ActivityManager.TaskDescription; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; @@ -40,6 +42,7 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.WindowManager; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; @@ -173,6 +176,31 @@ final class LetterboxUiController { : mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(); } + float getFixedOrientationLetterboxAspectRatio(Configuration parentConfiguration) { + // Don't check resolved windowing mode because it may not be updated yet during + // configuration change. + if (!isReachabilityEnabled(parentConfiguration)) { + return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio(); + } + + int dividerWindowWidth = + getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_thickness); + int dividerInsets = + getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_insets); + int dividerSize = dividerWindowWidth - dividerInsets * 2; + + // Getting the same aspect ratio that apps get in split screen. + Rect bounds = new Rect(parentConfiguration.windowConfiguration.getAppBounds()); + bounds.inset(dividerSize, /* dy */ 0); + bounds.right = bounds.centerX(); + + return computeAspectRatio(bounds); + } + + Resources getResources() { + return mActivityRecord.mWmService.mContext.getResources(); + } + private void handleDoubleTap() { if (!isReachabilityEnabled() || mActivityRecord.isInTransition()) { return; @@ -333,7 +361,7 @@ final class LetterboxUiController { } pw.println(prefix + " letterboxReason=" + getLetterboxReasonString(mainWin)); - pw.println(prefix + " letterboxAspectRatio=" + pw.println(prefix + " activityAspectRatio=" + mActivityRecord.computeAspectRatio(mActivityRecord.getBounds())); boolean shouldShowLetterboxUi = shouldShowLetterboxUi(mainWin); @@ -360,6 +388,9 @@ final class LetterboxUiController { pw.println(prefix + " isReachabilityEnabled=" + isReachabilityEnabled()); pw.println(prefix + " letterboxHorizontalPositionMultiplier=" + getHorizontalPositionMultiplier(mActivityRecord.getParent().getConfiguration())); + pw.println(prefix + " fixedOrientationLetterboxAspectRatio=" + + getFixedOrientationLetterboxAspectRatio( + mActivityRecord.getParent().getConfiguration())); } /**