diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 219d0650588f7..e1eb5a99a8045 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4915,16 +4915,15 @@ device orientation. --> false - - - 0.9 - + + 1 false diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4e8d915ca295e..8b8ecdd45ba30 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4262,7 +4262,7 @@ - + diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 45411a946f55e..4b98013a99cc1 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -36,6 +36,7 @@ import android.view.WindowManager; import com.android.server.UiThread; +import java.util.function.IntConsumer; import java.util.function.Supplier; /** @@ -70,7 +71,7 @@ public class Letterbox { private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow"); private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom }; // Reachability gestures. - private final Runnable mDoubleTapCallback; + private final IntConsumer mDoubleTapCallback; /** * Constructs a Letterbox. @@ -84,7 +85,7 @@ public class Letterbox { Supplier hasWallpaperBackgroundSupplier, Supplier blurRadiusSupplier, Supplier darkScrimAlphaSupplier, - Runnable doubleTapCallback) { + IntConsumer doubleTapCallback) { mSurfaceControlFactory = surfaceControlFactory; mTransactionFactory = transactionFactory; mAreCornersRounded = areCornersRounded; @@ -262,7 +263,7 @@ public class Letterbox { @Override public boolean onDoubleTapEvent(MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_UP) { - mDoubleTapCallback.run(); + mDoubleTapCallback.accept((int) e.getX()); return true; } return false; diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 72fbfcc2959e2..cbb473c10c6d7 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -54,6 +54,27 @@ final class LetterboxConfiguration { /** Using wallpaper as a background which can be blurred or dimmed with dark scrim. */ static final int LETTERBOX_BACKGROUND_WALLPAPER = 3; + /** + * Enum for Letterbox reachability position types. + * + *

Order from left to right is important since it's used in {@link + * #movePositionForReachabilityToNextRightStop} and {@link + * #movePositionForReachabilityToNextLeftStop}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({LETTERBOX_REACHABILITY_POSITION_LEFT, LETTERBOX_REACHABILITY_POSITION_CENTER, + LETTERBOX_REACHABILITY_POSITION_RIGHT}) + @interface LetterboxReachabilityPosition {}; + + /** Letterboxed app window is aligned to the left side. */ + static final int LETTERBOX_REACHABILITY_POSITION_LEFT = 0; + + /** Letterboxed app window is positioned in the horizontal center. */ + static final int LETTERBOX_REACHABILITY_POSITION_CENTER = 1; + + /** Letterboxed app window is aligned to the right side. */ + static final int LETTERBOX_REACHABILITY_POSITION_RIGHT = 2; + final Context mContext; // Aspect ratio of letterbox for fixed orientation, values <= @@ -85,25 +106,25 @@ 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; + // Default horizontal position the letterboxed app window when reachability is enabled and + // an app is fullscreen in landscape device orientatio. + // It is used as a starting point for mLetterboxPositionForReachability. + @LetterboxReachabilityPosition + private int mDefaultPositionForReachability; // 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 + // Horizontal position of a center of the letterboxed app window which is 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; + @LetterboxReachabilityPosition + private volatile int mLetterboxPositionForReachability; LetterboxConfiguration(Context systemUiContext) { mContext = systemUiContext; @@ -120,9 +141,8 @@ final class LetterboxConfiguration { R.dimen.config_letterboxHorizontalPositionMultiplier); mIsReachabilityEnabled = mContext.getResources().getBoolean( R.bool.config_letterboxIsReachabilityEnabled); - mDefaultPositionMultiplierForReachability = mContext.getResources().getFloat( - R.dimen.config_letterboxDefaultPositionMultiplierForReachability); - mLetterboxHorizontalMultiplierForReachability = mDefaultPositionMultiplierForReachability; + mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext); + mLetterboxPositionForReachability = mDefaultPositionForReachability; } /** @@ -395,58 +415,90 @@ final class LetterboxConfiguration { } /* - * 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. + * Gets default horizontal position of the letterboxed app window when reachability is enabled. + * Specified in {@link R.integer.config_letterboxDefaultPositionForReachability} or via an ADB + * command. */ - float getDefaultPositionMultiplierForReachability() { - return (mDefaultPositionMultiplierForReachability < 0.0f - || mDefaultPositionMultiplierForReachability > 1.0f) - // Default to a right position if invalid value is provided. - ? 1.0f : mDefaultPositionMultiplierForReachability; + @LetterboxReachabilityPosition + int getDefaultPositionForReachability() { + return mDefaultPositionForReachability; } /** - * 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. + * Overrides default horizonal position of the letterboxed app window when reachability + * is enabled. */ - void setDefaultPositionMultiplierForReachability(float multiplier) { - mDefaultPositionMultiplierForReachability = multiplier; + void setDefaultPositionForReachability(@LetterboxReachabilityPosition int position) { + mDefaultPositionForReachability = position; } /** - * Resets default horizontal position of a center of the letterboxed app window when - * reachability is enabled to {@link - * R.dimen.config_letterboxDefaultPositionMultiplierForReachability}. + * Resets default horizontal position of the letterboxed app window when reachability is + * enabled to {@link R.integer.config_letterboxDefaultPositionForReachability}. */ - void resetDefaultPositionMultiplierForReachability() { - mDefaultPositionMultiplierForReachability = mContext.getResources().getFloat( - R.dimen.config_letterboxDefaultPositionMultiplierForReachability); + void resetDefaultPositionForReachability() { + mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext); + } + + @LetterboxReachabilityPosition + private static int readLetterboxReachabilityPositionFromConfig(Context context) { + int position = context.getResources().getInteger( + R.integer.config_letterboxDefaultPositionForReachability); + return position == LETTERBOX_REACHABILITY_POSITION_LEFT + || position == LETTERBOX_REACHABILITY_POSITION_CENTER + || position == LETTERBOX_REACHABILITY_POSITION_RIGHT + ? position : LETTERBOX_REACHABILITY_POSITION_CENTER; } /* * 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. + *

The position multiplier is changed after each double tap in the letterbox area. */ float getHorizontalMultiplierForReachability() { - return mLetterboxHorizontalMultiplierForReachability; + switch (mLetterboxPositionForReachability) { + case LETTERBOX_REACHABILITY_POSITION_LEFT: + return 0.0f; + case LETTERBOX_REACHABILITY_POSITION_CENTER: + return 0.5f; + case LETTERBOX_REACHABILITY_POSITION_RIGHT: + return 1.0f; + default: + throw new AssertionError( + "Unexpected letterbox position type: " + mLetterboxPositionForReachability); + } + } + + /** Returns a string representing the given {@link LetterboxReachabilityPosition}. */ + static String letterboxReachabilityPositionToString( + @LetterboxReachabilityPosition int position) { + switch (position) { + case LETTERBOX_REACHABILITY_POSITION_LEFT: + return "LETTERBOX_REACHABILITY_POSITION_LEFT"; + case LETTERBOX_REACHABILITY_POSITION_CENTER: + return "LETTERBOX_REACHABILITY_POSITION_CENTER"; + case LETTERBOX_REACHABILITY_POSITION_RIGHT: + return "LETTERBOX_REACHABILITY_POSITION_RIGHT"; + default: + throw new AssertionError( + "Unexpected letterbox position type: " + position); + } } /** - * 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. + * Changes letterbox position for reachability to the next available one on the right side. */ - void flipHorizontalMultiplierForReachability() { - mLetterboxHorizontalMultiplierForReachability = - 1.0f - mLetterboxHorizontalMultiplierForReachability; + void movePositionForReachabilityToNextRightStop() { + mLetterboxPositionForReachability = Math.min( + mLetterboxPositionForReachability + 1, LETTERBOX_REACHABILITY_POSITION_RIGHT); + } + + /** + * Changes letterbox position for reachability to the next available one on the left side. + */ + void movePositionForReachabilityToNextLeftStop() { + mLetterboxPositionForReachability = Math.max(mLetterboxPositionForReachability - 1, 0); } } diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index c712c04b72ee3..7d073573835ff 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -210,12 +210,23 @@ final class LetterboxUiController { return mActivityRecord.mWmService.mContext.getResources(); } - private void handleDoubleTap() { + private void handleDoubleTap(int x) { if (!isReachabilityEnabled() || mActivityRecord.isInTransition()) { return; } - mLetterboxConfiguration.flipHorizontalMultiplierForReachability(); + if (mLetterbox.getInnerFrame().left <= x && mLetterbox.getInnerFrame().right >= x) { + // Only react to clicks at the sides of the letterboxed app window. + return; + } + + if (mLetterbox.getInnerFrame().left > x) { + // Moving to the next stop on the left side of the app window: right > center > left. + mLetterboxConfiguration.movePositionForReachabilityToNextLeftStop(); + } else if (mLetterbox.getInnerFrame().right < x) { + // Moving to the next stop on the right side of the app window: left > center > right. + mLetterboxConfiguration.movePositionForReachabilityToNextRightStop(); + } // TODO(197549949): Add animation for transition. mActivityRecord.recomputeConfiguration(); diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 47d7f030bcaab..0f8587c999583 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -23,6 +23,9 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER; +import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_CENTER; +import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_LEFT; +import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_RIGHT; import android.content.res.Resources.NotFoundException; import android.graphics.Color; @@ -44,6 +47,7 @@ import com.android.internal.protolog.ProtoLogImpl; import com.android.server.LocalServices; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; +import com.android.server.wm.LetterboxConfiguration.LetterboxReachabilityPosition; import java.io.IOException; import java.io.PrintWriter; @@ -787,22 +791,33 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } - private int runSetLetterboxDefaultPositionMultiplierForReachability(PrintWriter pw) + private int runSetLetterboxDefaultPositionForReachability(PrintWriter pw) throws RemoteException { - final float multiplier; + @LetterboxReachabilityPosition final int position; try { String arg = getNextArgRequired(); - multiplier = Float.parseFloat(arg); - } catch (NumberFormatException e) { - getErrPrintWriter().println("Error: bad multiplier format " + e); - return -1; + switch (arg) { + case "left": + position = LETTERBOX_REACHABILITY_POSITION_LEFT; + break; + case "center": + position = LETTERBOX_REACHABILITY_POSITION_CENTER; + break; + case "right": + position = LETTERBOX_REACHABILITY_POSITION_RIGHT; + break; + default: + getErrPrintWriter().println( + "Error: 'left', 'center' or 'right' are expected as an argument"); + return -1; + } } catch (IllegalArgumentException e) { getErrPrintWriter().println( - "Error: multiplier should be provided as an argument " + e); + "Error: 'left', 'center' or 'right' are expected as an argument" + e); return -1; } synchronized (mInternal.mGlobalLock) { - mLetterboxConfiguration.setDefaultPositionMultiplierForReachability(multiplier); + mLetterboxConfiguration.setDefaultPositionForReachability(position); } return 0; } @@ -841,8 +856,8 @@ public class WindowManagerShellCommand extends ShellCommand { case "--isReachabilityEnabled": runSetLetterboxIsReachabilityEnabled(pw); break; - case "--defaultPositionMultiplierReachability": - runSetLetterboxDefaultPositionMultiplierForReachability(pw); + case "--defaultPositionForReachability": + runSetLetterboxDefaultPositionForReachability(pw); break; default: getErrPrintWriter().println( @@ -885,8 +900,8 @@ public class WindowManagerShellCommand extends ShellCommand { case "isReachabilityEnabled": mLetterboxConfiguration.getIsReachabilityEnabled(); break; - case "defaultPositionMultiplierForReachability": - mLetterboxConfiguration.getDefaultPositionMultiplierForReachability(); + case "defaultPositionForReachability": + mLetterboxConfiguration.getDefaultPositionForReachability(); break; default: getErrPrintWriter().println( @@ -982,7 +997,7 @@ public class WindowManagerShellCommand extends ShellCommand { mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha(); mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier(); mLetterboxConfiguration.resetIsReachabilityEnabled(); - mLetterboxConfiguration.resetDefaultPositionMultiplierForReachability(); + mLetterboxConfiguration.resetDefaultPositionForReachability(); } } @@ -996,8 +1011,9 @@ public class WindowManagerShellCommand extends ShellCommand { + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio()); pw.println("Is reachability enabled: " + mLetterboxConfiguration.getIsReachabilityEnabled()); - pw.println("Default position multiplier for reachability: " - + mLetterboxConfiguration.getDefaultPositionMultiplierForReachability()); + pw.println("Default position for reachability: " + + LetterboxConfiguration.letterboxReachabilityPositionToString( + mLetterboxConfiguration.getDefaultPositionForReachability())); pw.println("Background type: " + LetterboxConfiguration.letterboxBackgroundTypeToString( @@ -1135,11 +1151,9 @@ public class WindowManagerShellCommand extends ShellCommand { 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(" --defaultPositionForReachability [left|center|right]"); + pw.println(" Default horizontal position of app window when reachability is."); + pw.println(" enabled."); pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType"); pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha"); pw.println(" |horizontalPositionMultiplier|isReachabilityEnabled"); 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 78946fca7e8b8..1e86522a23073 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -63,7 +63,7 @@ public class LetterboxTest { mLetterbox = new Letterbox(mSurfaces, StubTransaction::new, () -> mAreCornersRounded, () -> Color.valueOf(mColor), () -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha, - /* doubleTapCallback= */ () -> {}); + /* doubleTapCallback= */ x -> {}); mTransaction = spy(StubTransaction.class); }