Allow letterbox to move up/down for landscape-only apps in portrait mode

Fix: 226901995
Test: atest WmTests:SizeCompatTests
Change-Id: Ibe60793b381e61d56f57f8d2309754eedc84bddf
This commit is contained in:
Vali Calinescu
2022-04-22 15:28:49 +00:00
parent 4c81f0577b
commit 49ae8b0c3e
10 changed files with 751 additions and 207 deletions

View File

@@ -5133,16 +5133,24 @@
-->
<color name="config_letterboxBackgroundColor">@android:color/system_neutral2_900</color>
<!-- Horizonal position of a center of the letterboxed app window.
<!-- 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. If given value < 0
or > 1, it is ignored and central positionis used (0.5). -->
or > 1, it is ignored and central position is used (0.5). -->
<item name="config_letterboxHorizontalPositionMultiplier" format="float" type="dimen">0.5</item>
<!-- Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
device orientation. -->
<bool name="config_letterboxIsReachabilityEnabled">false</bool>
<!-- Vertical position of a center of the letterboxed app window.
0 corresponds to the upper side of the screen and 1 to the lower side. If given value < 0
or > 1, it is ignored and central position is used (0.5). -->
<item name="config_letterboxVerticalPositionMultiplier" format="float" type="dimen">0.5</item>
<!-- Default horizonal position of the letterboxed app window when reachability is
<!-- Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps.
-->
<bool name="config_letterboxIsHorizontalReachabilityEnabled">false</bool>
<!-- Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps. -->
<bool name="config_letterboxIsVerticalReachabilityEnabled">false</bool>
<!-- Default horizontal position of the letterboxed app window when reachability is
enabled and an app is fullscreen in landscape device orientation. When reachability is
enabled, the position can change between left, center and right. This config defines the
default one:
@@ -5150,7 +5158,17 @@
- Option 1 - Center.
- Option 2 - Right.
If given value is outside of this range, the option 1 (center) is assummed. -->
<integer name="config_letterboxDefaultPositionForReachability">1</integer>
<integer name="config_letterboxDefaultPositionForHorizontalReachability">1</integer>
<!-- Default vertical position of the letterboxed app window when reachability is
enabled and an app is fullscreen in portrait device orientation. When reachability is
enabled, the position can change between top, center and bottom. This config defines the
default one:
- Option 0 - Top.
- Option 1 - Center.
- Option 2 - Bottom.
If given value is outside of this range, the option 1 (center) is assummed. -->
<integer name="config_letterboxDefaultPositionForVerticalReachability">1</integer>
<!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. -->
<bool name="config_letterboxIsEducationEnabled">false</bool>

View File

@@ -4384,8 +4384,11 @@
<java-symbol type="integer" name="config_letterboxBackgroundType" />
<java-symbol type="color" name="config_letterboxBackgroundColor" />
<java-symbol type="dimen" name="config_letterboxHorizontalPositionMultiplier" />
<java-symbol type="bool" name="config_letterboxIsReachabilityEnabled" />
<java-symbol type="integer" name="config_letterboxDefaultPositionForReachability" />
<java-symbol type="dimen" name="config_letterboxVerticalPositionMultiplier" />
<java-symbol type="bool" name="config_letterboxIsHorizontalReachabilityEnabled" />
<java-symbol type="bool" name="config_letterboxIsVerticalReachabilityEnabled" />
<java-symbol type="integer" name="config_letterboxDefaultPositionForHorizontalReachability" />
<java-symbol type="integer" name="config_letterboxDefaultPositionForVerticalReachability" />
<java-symbol type="bool" name="config_letterboxIsEducationEnabled" />
<java-symbol type="bool" name="config_isCameraCompatControlForStretchedIssuesEnabled" />

View File

@@ -7727,7 +7727,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (isFixedOrientationLetterboxAllowed || mCompatDisplayInsets != null
// In fullscreen, can be letterboxed for aspect ratio.
|| !inMultiWindowMode()) {
updateResolvedBoundsHorizontalPosition(newParentConfiguration);
updateResolvedBoundsPosition(newParentConfiguration);
}
if (mVisibleRequested) {
@@ -7830,39 +7830,61 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
* Adjusts horizontal position of resolved bounds if they doesn't fill the parent using gravity
* Adjusts position of resolved bounds if they doesn't fill the parent using gravity
* requested in the config or via an ADB command. For more context see {@link
* LetterboxUiController#getHorizontalPositionMultiplier(Configuration)}.
* LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and
* {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)}
*/
private void updateResolvedBoundsHorizontalPosition(Configuration newParentConfiguration) {
private void updateResolvedBoundsPosition(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
final Rect screenResolvedBounds =
mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
if (resolvedBounds.isEmpty() || parentBounds.width() == screenResolvedBounds.width()) {
if (resolvedBounds.isEmpty()) {
return;
}
// Horizontal position
int offsetX = 0;
if (screenResolvedBounds.width() >= parentAppBounds.width()) {
// If resolved bounds overlap with insets, center within app bounds.
offsetX = getHorizontalCenterOffset(
parentAppBounds.width(), screenResolvedBounds.width());
} else {
float positionMultiplier =
mLetterboxUiController.getHorizontalPositionMultiplier(newParentConfiguration);
offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
* positionMultiplier);
if (parentBounds.width() != screenResolvedBounds.width()) {
if (screenResolvedBounds.width() >= parentAppBounds.width()) {
// If resolved bounds overlap with insets, center within app bounds.
offsetX = getCenterOffset(
parentAppBounds.width(), screenResolvedBounds.width());
} else {
float positionMultiplier =
mLetterboxUiController.getHorizontalPositionMultiplier(
newParentConfiguration);
offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
* positionMultiplier);
}
}
// Vertical position
int offsetY = 0;
if (parentBounds.height() != screenResolvedBounds.height()) {
if (screenResolvedBounds.height() >= parentAppBounds.height()) {
// If resolved bounds overlap with insets, center within app bounds.
offsetY = getCenterOffset(
parentAppBounds.height(), screenResolvedBounds.height());
} else {
float positionMultiplier =
mLetterboxUiController.getVerticalPositionMultiplier(
newParentConfiguration);
offsetY = (int) Math.ceil((parentAppBounds.height() - screenResolvedBounds.height())
* positionMultiplier);
}
}
if (mSizeCompatBounds != null) {
mSizeCompatBounds.offset(offsetX, 0 /* offsetY */);
mSizeCompatBounds.offset(offsetX , offsetY);
final int dy = mSizeCompatBounds.top - resolvedBounds.top;
final int dx = mSizeCompatBounds.left - resolvedBounds.left;
offsetBounds(resolvedConfig, dx, 0 /* offsetY */);
offsetBounds(resolvedConfig, dx, dy);
} else {
offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
offsetBounds(resolvedConfig, offsetX, offsetY);
}
// Since bounds has changed, the configuration needs to be computed accordingly.
@@ -8077,14 +8099,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
containingBounds, desiredAspectRatio, true);
// Vertically center if orientation is landscape. Center within parent bounds with insets
// to ensure that insets do not trim height. Bounds will later be horizontally centered in
// {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
if (forcedOrientation == ORIENTATION_LANDSCAPE) {
final int offsetY = parentBoundsWithInsets.centerY() - resolvedBounds.centerY();
resolvedBounds.offset(0, offsetY);
}
if (mCompatDisplayInsets != null) {
mCompatDisplayInsets.getBoundsByRotation(
mTmpBounds, newParentConfig.windowConfiguration.getRotation());
@@ -8107,10 +8121,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* Resolves aspect ratio restrictions for an activity. If the bounds are restricted by
* aspect ratio, the position will be adjusted later in {@link
* updateResolvedBoundsHorizontalPosition} within parent's app bounds to balance the visual
* appearance. The policy of aspect ratio has higher priority than the requested override
* bounds.
* aspect ratio, the position will be adjusted later in {@link #updateResolvedBoundsPosition
* within parent's app bounds to balance the visual appearance. The policy of aspect ratio has
* higher priority than the requested override bounds.
*/
private void resolveAspectRatioRestriction(Configuration newParentConfiguration) {
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
@@ -8122,7 +8135,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mTmpBounds.setEmpty();
mIsAspectRatioApplied = applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
// If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
// then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
// then they should be aligned later in #updateResolvedBoundsPosition()
if (!mTmpBounds.isEmpty()) {
resolvedBounds.set(mTmpBounds);
}
@@ -8256,22 +8269,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
forAllWindows(WindowState::updateGlobalScale, false /* traverseTopToBottom */);
}
// Vertically center within parent (bounds) - this is a UX choice and exclude the horizontal
// decor if needed. Horizontal position is adjusted in
// updateResolvedBoundsHorizontalPosition.
// The position will be later adjusted in updateResolvedBoundsPosition.
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
final boolean fillContainer = resolvedBounds.equals(containingBounds);
final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
// If the activity is not in size compat mode, calculate vertical centering
// from the container and resolved bounds.
// If the activity is in size compat mode, calculate vertical centering
// from the container and size compat bounds.
// The container bounds contain the parent bounds offset in the display, for
// example when an activity is in the lower split of split screen.
final int screenPosY = (mSizeCompatBounds == null
? (containerBounds.height() - resolvedBounds.height()) / 2
: (containerBounds.height() - mSizeCompatBounds.height()) / 2)
+ containerBounds.top;
final int screenPosY = fillContainer ? containerBounds.top : containerAppBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
if (mSizeCompatBounds != null) {
@@ -8331,9 +8333,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return true;
}
/** @return The horizontal offset of putting the content in the center of viewport. */
private static int getHorizontalCenterOffset(int viewportW, int contentW) {
return (int) ((viewportW - contentW + 1) * 0.5f);
/** @return The horizontal / vertical offset of putting the content in the center of viewport.*/
private static int getCenterOffset(int viewportDim, int contentDim) {
return (int) ((viewportDim - contentDim + 1) * 0.5f);
}
private static void offsetBounds(Configuration inOutConfig, int offsetX, int offsetY) {
@@ -9595,7 +9597,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
outBounds.bottom = dH;
outBounds.right = (int) ((float) dH * dH / dW);
}
outBounds.offset(getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
outBounds.offset(getCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
}
outAppBounds.set(outBounds);

View File

@@ -72,7 +72,8 @@ public class Letterbox {
private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow");
private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom };
// Reachability gestures.
private final IntConsumer mDoubleTapCallback;
private final IntConsumer mDoubleTapCallbackX;
private final IntConsumer mDoubleTapCallbackY;
/**
* Constructs a Letterbox.
@@ -86,7 +87,8 @@ public class Letterbox {
Supplier<Boolean> hasWallpaperBackgroundSupplier,
Supplier<Integer> blurRadiusSupplier,
Supplier<Float> darkScrimAlphaSupplier,
IntConsumer doubleTapCallback) {
IntConsumer doubleTapCallbackX,
IntConsumer doubleTapCallbackY) {
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
mAreCornersRounded = areCornersRounded;
@@ -94,7 +96,8 @@ public class Letterbox {
mHasWallpaperBackgroundSupplier = hasWallpaperBackgroundSupplier;
mBlurRadiusSupplier = blurRadiusSupplier;
mDarkScrimAlphaSupplier = darkScrimAlphaSupplier;
mDoubleTapCallback = doubleTapCallback;
mDoubleTapCallbackX = doubleTapCallbackX;
mDoubleTapCallbackY = doubleTapCallbackY;
}
/**
@@ -264,7 +267,8 @@ public class Letterbox {
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_UP) {
mDoubleTapCallback.accept((int) e.getX());
mDoubleTapCallbackX.accept((int) e.getX());
mDoubleTapCallbackY.accept((int) e.getY());
return true;
}
return false;

View File

@@ -55,25 +55,48 @@ final class LetterboxConfiguration {
static final int LETTERBOX_BACKGROUND_WALLPAPER = 3;
/**
* Enum for Letterbox reachability position types.
* Enum for Letterbox horizontal reachability position types.
*
* <p>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 {};
@IntDef({LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT})
@interface LetterboxHorizontalReachabilityPosition {};
/** Letterboxed app window is aligned to the left side. */
static final int LETTERBOX_REACHABILITY_POSITION_LEFT = 0;
static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT = 0;
/** Letterboxed app window is positioned in the horizontal center. */
static final int LETTERBOX_REACHABILITY_POSITION_CENTER = 1;
static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER = 1;
/** Letterboxed app window is aligned to the right side. */
static final int LETTERBOX_REACHABILITY_POSITION_RIGHT = 2;
static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT = 2;
/**
* Enum for Letterbox vertical reachability position types.
*
* <p>Order from top to bottom is important since it's used in {@link
* #movePositionForReachabilityToNextBottomStop} and {@link
* #movePositionForReachabilityToNextTopStop}.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM})
@interface LetterboxVerticalReachabilityPosition {};
/** Letterboxed app window is aligned to the left side. */
static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP = 0;
/** Letterboxed app window is positioned in the vertical center. */
static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER = 1;
/** Letterboxed app window is aligned to the right side. */
static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM = 2;
final Context mContext;
@@ -106,25 +129,50 @@ final class LetterboxConfiguration {
// side of the screen and 1.0 to the right side.
private float mLetterboxHorizontalPositionMultiplier;
// 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;
// Vertical position of a center of the letterboxed app window. 0 corresponds to the top
// side of the screen and 1.0 to the bottom side.
private float mLetterboxVerticalPositionMultiplier;
// Default horizontal position the letterboxed app window when horizontal reachability is
// enabled and an app is fullscreen in landscape device orientation.
// It is used as a starting point for mLetterboxPositionForHorizontalReachability.
@LetterboxHorizontalReachabilityPosition
private int mDefaultPositionForHorizontalReachability;
// Default vertical position the letterboxed app window when vertical reachability is enabled
// and an app is fullscreen in portrait device orientation.
// It is used as a starting point for mLetterboxPositionForVerticalReachability.
@LetterboxVerticalReachabilityPosition
private int mDefaultPositionForVerticalReachability;
// Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in
// landscape device orientation.
private boolean mIsHorizontalReachabilityEnabled;
// Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in
// portrait device orientation.
private boolean mIsVerticalReachabilityEnabled;
// 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 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.
// ActivityRecord#updateResolvedBoundsPosition.
// TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
// Overview after changing position in another app.
@LetterboxReachabilityPosition
private volatile int mLetterboxPositionForReachability;
@LetterboxHorizontalReachabilityPosition
private volatile int mLetterboxPositionForHorizontalReachability;
// Vertical 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#getVerticalPositionMultiplier which is called from
// ActivityRecord#updateResolvedBoundsPosition.
// TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
// Overview after changing position in another app.
@LetterboxVerticalReachabilityPosition
private volatile int mLetterboxPositionForVerticalReachability;
// Whether education is allowed for letterboxed fullscreen apps.
private boolean mIsEducationEnabled;
@@ -142,10 +190,16 @@ final class LetterboxConfiguration {
R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
R.dimen.config_letterboxHorizontalPositionMultiplier);
mIsReachabilityEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsReachabilityEnabled);
mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext);
mLetterboxPositionForReachability = mDefaultPositionForReachability;
mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsHorizontalReachabilityEnabled);
mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsVerticalReachabilityEnabled);
mDefaultPositionForHorizontalReachability =
readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
mDefaultPositionForVerticalReachability =
readLetterboxVerticalReachabilityPositionFromConfig(mContext);
mLetterboxPositionForHorizontalReachability = mDefaultPositionForHorizontalReachability;
mLetterboxPositionForVerticalReachability = mDefaultPositionForVerticalReachability;
mIsEducationEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsEducationEnabled);
}
@@ -375,6 +429,19 @@ final class LetterboxConfiguration {
? 0.5f : mLetterboxHorizontalPositionMultiplier;
}
/*
* Gets vertical position of a center of the letterboxed app window specified
* in {@link com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier}
* or via an ADB command. 0 corresponds to the top side of the screen and 1 to the
* bottom side.
*/
float getLetterboxVerticalPositionMultiplier() {
return (mLetterboxVerticalPositionMultiplier < 0.0f
|| mLetterboxVerticalPositionMultiplier > 1.0f)
// Default to central position if invalid value is provided.
? 0.5f : mLetterboxVerticalPositionMultiplier;
}
/**
* Overrides horizontal position of a center of the letterboxed app window. If given value < 0
* or > 1, then it and a value of {@link
@@ -385,6 +452,16 @@ final class LetterboxConfiguration {
mLetterboxHorizontalPositionMultiplier = multiplier;
}
/**
* Overrides vertical position of a center of the letterboxed app window. If given value < 0
* or > 1, then it and a value of {@link
* com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier} are ignored and
* central position (0.5) is used.
*/
void setLetterboxVerticalPositionMultiplier(float multiplier) {
mLetterboxVerticalPositionMultiplier = multiplier;
}
/**
* Resets horizontal position of a center of the letterboxed app window to {@link
* com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}.
@@ -394,65 +471,145 @@ final class LetterboxConfiguration {
com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
}
/*
* Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape
* device orientation.
/**
* Resets vertical position of a center of the letterboxed app window to {@link
* com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier}.
*/
boolean getIsReachabilityEnabled() {
return mIsReachabilityEnabled;
void resetLetterboxVerticalPositionMultiplier() {
mLetterboxVerticalPositionMultiplier = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier);
}
/**
* Overrides whether reachability repositioning is allowed for letterboxed fullscreen apps in
/*
* Whether horizontal 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);
boolean getIsHorizontalReachabilityEnabled() {
return mIsHorizontalReachabilityEnabled;
}
/*
* 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.
* Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in
* portrait device orientation.
*/
@LetterboxReachabilityPosition
int getDefaultPositionForReachability() {
return mDefaultPositionForReachability;
boolean getIsVerticalReachabilityEnabled() {
return mIsVerticalReachabilityEnabled;
}
/**
* Overrides default horizonal position of the letterboxed app window when reachability
* Overrides whether horizontal reachability repositioning is allowed for letterboxed fullscreen
* apps in landscape device orientation.
*/
void setIsHorizontalReachabilityEnabled(boolean enabled) {
mIsHorizontalReachabilityEnabled = enabled;
}
/**
* Overrides whether vertical reachability repositioning is allowed for letterboxed fullscreen
* apps in portrait device orientation.
*/
void setIsVerticalReachabilityEnabled(boolean enabled) {
mIsVerticalReachabilityEnabled = enabled;
}
/**
* Resets whether horizontal reachability repositioning is allowed for letterboxed fullscreen
* apps in landscape device orientation to
* {@link R.bool.config_letterboxIsHorizontalReachabilityEnabled}.
*/
void resetIsHorizontalReachabilityEnabled() {
mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsHorizontalReachabilityEnabled);
}
/**
* Resets whether vertical reachability repositioning is allowed for letterboxed fullscreen apps
* in portrait device orientation to
* {@link R.bool.config_letterboxIsVerticalReachabilityEnabled}.
*/
void resetIsVerticalReachabilityEnabled() {
mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean(
R.bool.config_letterboxIsVerticalReachabilityEnabled);
}
/*
* Gets default horizontal position of the letterboxed app window when horizontal reachability
* is enabled.
*
* <p> Specified in {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability}
* or via an ADB command.
*/
void setDefaultPositionForReachability(@LetterboxReachabilityPosition int position) {
mDefaultPositionForReachability = position;
@LetterboxHorizontalReachabilityPosition
int getDefaultPositionForHorizontalReachability() {
return mDefaultPositionForHorizontalReachability;
}
/*
* Gets default vertical position of the letterboxed app window when vertical reachability is
* enabled.
*
* <p> Specified in {@link R.integer.config_letterboxDefaultPositionForVerticalReachability} or
* via an ADB command.
*/
@LetterboxVerticalReachabilityPosition
int getDefaultPositionForVerticalReachability() {
return mDefaultPositionForVerticalReachability;
}
/**
* Resets default horizontal position of the letterboxed app window when reachability is
* enabled to {@link R.integer.config_letterboxDefaultPositionForReachability}.
* Overrides default horizontal position of the letterboxed app window when horizontal
* reachability is enabled.
*/
void resetDefaultPositionForReachability() {
mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext);
void setDefaultPositionForHorizontalReachability(
@LetterboxHorizontalReachabilityPosition int position) {
mDefaultPositionForHorizontalReachability = position;
}
@LetterboxReachabilityPosition
private static int readLetterboxReachabilityPositionFromConfig(Context context) {
/**
* Overrides default vertical position of the letterboxed app window when vertical
* reachability is enabled.
*/
void setDefaultPositionForVerticalReachability(
@LetterboxVerticalReachabilityPosition int position) {
mDefaultPositionForVerticalReachability = position;
}
/**
* Resets default horizontal position of the letterboxed app window when horizontal reachability
* is enabled to {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability}.
*/
void resetDefaultPositionForHorizontalReachability() {
mDefaultPositionForHorizontalReachability =
readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
}
/**
* Resets default vertical position of the letterboxed app window when vertical reachability
* is enabled to {@link R.integer.config_letterboxDefaultPositionForVerticalReachability}.
*/
void resetDefaultPositionForVerticalReachability() {
mDefaultPositionForVerticalReachability =
readLetterboxVerticalReachabilityPositionFromConfig(mContext);
}
@LetterboxHorizontalReachabilityPosition
private static int readLetterboxHorizontalReachabilityPositionFromConfig(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;
R.integer.config_letterboxDefaultPositionForHorizontalReachability);
return position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT
|| position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER
|| position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT
? position : LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
}
@LetterboxVerticalReachabilityPosition
private static int readLetterboxVerticalReachabilityPositionFromConfig(Context context) {
int position = context.getResources().getInteger(
R.integer.config_letterboxDefaultPositionForVerticalReachability);
return position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP
|| position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER
|| position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM
? position : LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
}
/*
@@ -462,48 +619,108 @@ final class LetterboxConfiguration {
* <p>The position multiplier is changed after each double tap in the letterbox area.
*/
float getHorizontalMultiplierForReachability() {
switch (mLetterboxPositionForReachability) {
case LETTERBOX_REACHABILITY_POSITION_LEFT:
switch (mLetterboxPositionForHorizontalReachability) {
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
return 0.0f;
case LETTERBOX_REACHABILITY_POSITION_CENTER:
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER:
return 0.5f;
case LETTERBOX_REACHABILITY_POSITION_RIGHT:
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT:
return 1.0f;
default:
throw new AssertionError(
"Unexpected letterbox position type: " + mLetterboxPositionForReachability);
"Unexpected letterbox position type: "
+ mLetterboxPositionForHorizontalReachability);
}
}
/*
* Gets vertical position of a center of the letterboxed app window when reachability
* is enabled specified. 0 corresponds to the top side of the screen and 1 to the bottom side.
*
* <p>The position multiplier is changed after each double tap in the letterbox area.
*/
float getVerticalMultiplierForReachability() {
switch (mLetterboxPositionForVerticalReachability) {
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
return 0.0f;
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER:
return 0.5f;
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM:
return 1.0f;
default:
throw new AssertionError(
"Unexpected letterbox position type: "
+ mLetterboxPositionForVerticalReachability);
}
}
/** Returns a string representing the given {@link LetterboxReachabilityPosition}. */
static String letterboxReachabilityPositionToString(
@LetterboxReachabilityPosition int position) {
/** Returns a string representing the given {@link LetterboxHorizontalReachabilityPosition}. */
static String letterboxHorizontalReachabilityPositionToString(
@LetterboxHorizontalReachabilityPosition 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";
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT";
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER:
return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER";
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT:
return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT";
default:
throw new AssertionError(
"Unexpected letterbox position type: " + position);
}
}
/**
* Changes letterbox position for reachability to the next available one on the right side.
*/
void movePositionForReachabilityToNextRightStop() {
mLetterboxPositionForReachability = Math.min(
mLetterboxPositionForReachability + 1, LETTERBOX_REACHABILITY_POSITION_RIGHT);
/** Returns a string representing the given {@link LetterboxVerticalReachabilityPosition}. */
static String letterboxVerticalReachabilityPositionToString(
@LetterboxVerticalReachabilityPosition int position) {
switch (position) {
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP";
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER:
return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER";
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM:
return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM";
default:
throw new AssertionError(
"Unexpected letterbox position type: " + position);
}
}
/**
* Changes letterbox position for reachability to the next available one on the left side.
* Changes letterbox position for horizontal reachability to the next available one on the
* right side.
*/
void movePositionForReachabilityToNextLeftStop() {
mLetterboxPositionForReachability = Math.max(mLetterboxPositionForReachability - 1, 0);
void movePositionForHorizontalReachabilityToNextRightStop() {
mLetterboxPositionForHorizontalReachability = Math.min(
mLetterboxPositionForHorizontalReachability + 1,
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT);
}
/**
* Changes letterbox position for horizontal reachability to the next available one on the left
* side.
*/
void movePositionForHorizontalReachabilityToNextLeftStop() {
mLetterboxPositionForHorizontalReachability =
Math.max(mLetterboxPositionForHorizontalReachability - 1, 0);
}
/**
* Changes letterbox position for vertical reachability to the next available one on the bottom
* side.
*/
void movePositionForVerticalReachabilityToNextBottomStop() {
mLetterboxPositionForVerticalReachability = Math.min(
mLetterboxPositionForVerticalReachability + 1,
LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM);
}
/**
* Changes letterbox position for vertical reachability to the next available one on the top
* side.
*/
void movePositionForVerticalReachabilityToNextTopStop() {
mLetterboxPositionForVerticalReachability =
Math.max(mLetterboxPositionForVerticalReachability - 1, 0);
}
/**

View File

@@ -163,7 +163,8 @@ final class LetterboxUiController {
this::hasWallpaperBackgroudForLetterbox,
this::getLetterboxWallpaperBlurRadius,
this::getLetterboxWallpaperDarkScrimAlpha,
this::handleDoubleTap);
this::handleHorizontalDoubleTap,
this::handleVerticalDoubleTap);
mLetterbox.attachInput(w);
}
mActivityRecord.getPosition(mTmpPoint);
@@ -193,17 +194,28 @@ 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)
return isHorizontalReachabilityEnabled(parentConfiguration)
// Using the last global dynamic position to avoid "jumps" when moving
// between apps or activities.
? mLetterboxConfiguration.getHorizontalMultiplierForReachability()
: mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier();
}
float getVerticalPositionMultiplier(Configuration parentConfiguration) {
// Don't check resolved configuration because it may not be updated yet during
// configuration change.
return isVerticalReachabilityEnabled(parentConfiguration)
// Using the last global dynamic position to avoid "jumps" when moving
// between apps or activities.
? mLetterboxConfiguration.getVerticalMultiplierForReachability()
: mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier();
}
float getFixedOrientationLetterboxAspectRatio(Configuration parentConfiguration) {
// Don't check resolved windowing mode because it may not be updated yet during
// configuration change.
if (!isReachabilityEnabled(parentConfiguration)) {
if (!isHorizontalReachabilityEnabled(parentConfiguration)
&& !isVerticalReachabilityEnabled(parentConfiguration)) {
return mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
}
@@ -225,8 +237,8 @@ final class LetterboxUiController {
return mActivityRecord.mWmService.mContext.getResources();
}
private void handleDoubleTap(int x) {
if (!isReachabilityEnabled() || mActivityRecord.isInTransition()) {
private void handleHorizontalDoubleTap(int x) {
if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) {
return;
}
@@ -237,10 +249,32 @@ final class LetterboxUiController {
if (mLetterbox.getInnerFrame().left > x) {
// Moving to the next stop on the left side of the app window: right > center > left.
mLetterboxConfiguration.movePositionForReachabilityToNextLeftStop();
mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextLeftStop();
} else if (mLetterbox.getInnerFrame().right < x) {
// Moving to the next stop on the right side of the app window: left > center > right.
mLetterboxConfiguration.movePositionForReachabilityToNextRightStop();
mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop();
}
// TODO(197549949): Add animation for transition.
mActivityRecord.recomputeConfiguration();
}
private void handleVerticalDoubleTap(int y) {
if (!isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) {
return;
}
if (mLetterbox.getInnerFrame().top <= y && mLetterbox.getInnerFrame().bottom >= y) {
// Only react to clicks at the top and bottom of the letterboxed app window.
return;
}
if (mLetterbox.getInnerFrame().top > y) {
// Moving to the next stop on the top side of the app window: bottom > center > top.
mLetterboxConfiguration.movePositionForVerticalReachabilityToNextTopStop();
} else if (mLetterbox.getInnerFrame().bottom < y) {
// Moving to the next stop on the bottom side of the app window: top > center > bottom.
mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop();
}
// TODO(197549949): Add animation for transition.
@@ -248,25 +282,47 @@ final class LetterboxUiController {
}
/**
* Whether reachability is enabled for an activity in the curren configuration.
* Whether horizontal reachability is enabled for an activity in the current configuration.
*
* <p>Conditions that needs to be met:
* <ul>
* <li>Activity is portrait-only.
* <li>Fullscreen window in landscape device orientation.
* <li>Reachability is enabled.
* <li>Horizontal Reachability is enabled.
* </ul>
*/
private boolean isReachabilityEnabled(Configuration parentConfiguration) {
return mLetterboxConfiguration.getIsReachabilityEnabled()
private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) {
return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
&& parentConfiguration.orientation == ORIENTATION_LANDSCAPE
&& mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT;
&& (parentConfiguration.orientation == ORIENTATION_LANDSCAPE
&& mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT);
}
private boolean isReachabilityEnabled() {
return isReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
private boolean isHorizontalReachabilityEnabled() {
return isHorizontalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
}
/**
* Whether vertical reachability is enabled for an activity in the current configuration.
*
* <p>Conditions that needs to be met:
* <ul>
* <li>Activity is landscape-only.
* <li>Fullscreen window in portrait device orientation.
* <li>Vertical Reachability is enabled.
* </ul>
*/
private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) {
return mLetterboxConfiguration.getIsVerticalReachabilityEnabled()
&& parentConfiguration.windowConfiguration.getWindowingMode()
== WINDOWING_MODE_FULLSCREEN
&& (parentConfiguration.orientation == ORIENTATION_PORTRAIT
&& mActivityRecord.getRequestedConfigurationOrientation() == ORIENTATION_LANDSCAPE);
}
private boolean isVerticalReachabilityEnabled() {
return isVerticalReachabilityEnabled(mActivityRecord.getParent().getConfiguration());
}
@VisibleForTesting
@@ -474,9 +530,13 @@ final class LetterboxUiController {
+ getLetterboxWallpaperBlurRadius());
}
pw.println(prefix + " isReachabilityEnabled=" + isReachabilityEnabled());
pw.println(prefix + " isHorizontalReachabilityEnabled="
+ isHorizontalReachabilityEnabled());
pw.println(prefix + " isVerticalReachabilityEnabled=" + isVerticalReachabilityEnabled());
pw.println(prefix + " letterboxHorizontalPositionMultiplier="
+ getHorizontalPositionMultiplier(mActivityRecord.getParent().getConfiguration()));
pw.println(prefix + " letterboxVerticalPositionMultiplier="
+ getVerticalPositionMultiplier(mActivityRecord.getParent().getConfiguration()));
pw.println(prefix + " fixedOrientationLetterboxAspectRatio="
+ getFixedOrientationLetterboxAspectRatio(
mActivityRecord.getParent().getConfiguration()));

View File

@@ -23,9 +23,12 @@ 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 static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
import android.content.res.Resources.NotFoundException;
import android.graphics.Color;
@@ -47,7 +50,8 @@ 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 com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
import com.android.server.wm.LetterboxConfiguration.LetterboxVerticalReachabilityPosition;
import java.io.IOException;
import java.io.PrintWriter;
@@ -773,7 +777,27 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
private int runSetLetterboxIsReachabilityEnabled(PrintWriter pw) throws RemoteException {
private int runSetLetterboxVerticalPositionMultiplier(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.setLetterboxVerticalPositionMultiplier(multiplier);
}
return 0;
}
private int runSetLetterboxIsHorizontalReachabilityEnabled(PrintWriter pw)
throws RemoteException {
String arg = getNextArg();
final boolean enabled;
switch (arg) {
@@ -791,25 +815,49 @@ public class WindowManagerShellCommand extends ShellCommand {
}
synchronized (mInternal.mGlobalLock) {
mLetterboxConfiguration.setIsReachabilityEnabled(enabled);
mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(enabled);
}
return 0;
}
private int runSetLetterboxDefaultPositionForReachability(PrintWriter pw)
private int runSetLetterboxIsVerticalReachabilityEnabled(PrintWriter pw)
throws RemoteException {
@LetterboxReachabilityPosition final int position;
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.setIsVerticalReachabilityEnabled(enabled);
}
return 0;
}
private int runSetLetterboxDefaultPositionForHorizontalReachability(PrintWriter pw)
throws RemoteException {
@LetterboxHorizontalReachabilityPosition final int position;
try {
String arg = getNextArgRequired();
switch (arg) {
case "left":
position = LETTERBOX_REACHABILITY_POSITION_LEFT;
position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
break;
case "center":
position = LETTERBOX_REACHABILITY_POSITION_CENTER;
position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
break;
case "right":
position = LETTERBOX_REACHABILITY_POSITION_RIGHT;
position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
break;
default:
getErrPrintWriter().println(
@@ -822,7 +870,38 @@ public class WindowManagerShellCommand extends ShellCommand {
return -1;
}
synchronized (mInternal.mGlobalLock) {
mLetterboxConfiguration.setDefaultPositionForReachability(position);
mLetterboxConfiguration.setDefaultPositionForHorizontalReachability(position);
}
return 0;
}
private int runSetLetterboxDefaultPositionForVerticalReachability(PrintWriter pw)
throws RemoteException {
@LetterboxVerticalReachabilityPosition final int position;
try {
String arg = getNextArgRequired();
switch (arg) {
case "top":
position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
break;
case "center":
position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
break;
case "bottom":
position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
break;
default:
getErrPrintWriter().println(
"Error: 'top', 'center' or 'bottom' are expected as an argument");
return -1;
}
} catch (IllegalArgumentException e) {
getErrPrintWriter().println(
"Error: 'top', 'center' or 'bottom' are expected as an argument" + e);
return -1;
}
synchronized (mInternal.mGlobalLock) {
mLetterboxConfiguration.setDefaultPositionForVerticalReachability(position);
}
return 0;
}
@@ -881,11 +960,20 @@ public class WindowManagerShellCommand extends ShellCommand {
case "--horizontalPositionMultiplier":
runSetLetterboxHorizontalPositionMultiplier(pw);
break;
case "--isReachabilityEnabled":
runSetLetterboxIsReachabilityEnabled(pw);
case "--verticalPositionMultiplier":
runSetLetterboxVerticalPositionMultiplier(pw);
break;
case "--defaultPositionForReachability":
runSetLetterboxDefaultPositionForReachability(pw);
case "--isHorizontalReachabilityEnabled":
runSetLetterboxIsHorizontalReachabilityEnabled(pw);
break;
case "--isVerticalReachabilityEnabled":
runSetLetterboxIsVerticalReachabilityEnabled(pw);
break;
case "--defaultPositionForHorizontalReachability":
runSetLetterboxDefaultPositionForHorizontalReachability(pw);
break;
case "--defaultPositionForVerticalReachability":
runSetLetterboxDefaultPositionForVerticalReachability(pw);
break;
case "--isEducationEnabled":
runSetLetterboxIsEducationEnabled(pw);
@@ -928,11 +1016,20 @@ public class WindowManagerShellCommand extends ShellCommand {
case "horizontalPositionMultiplier":
mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
break;
case "isReachabilityEnabled":
mLetterboxConfiguration.getIsReachabilityEnabled();
case "verticalPositionMultiplier":
mLetterboxConfiguration.resetLetterboxVerticalPositionMultiplier();
break;
case "defaultPositionForReachability":
mLetterboxConfiguration.getDefaultPositionForReachability();
case "isHorizontalReachabilityEnabled":
mLetterboxConfiguration.getIsHorizontalReachabilityEnabled();
break;
case "isVerticalReachabilityEnabled":
mLetterboxConfiguration.getIsVerticalReachabilityEnabled();
break;
case "defaultPositionForHorizontalReachability":
mLetterboxConfiguration.getDefaultPositionForHorizontalReachability();
break;
case "defaultPositionForVerticalReachability":
mLetterboxConfiguration.getDefaultPositionForVerticalReachability();
break;
case "isEducationEnabled":
mLetterboxConfiguration.getIsEducationEnabled();
@@ -1030,8 +1127,10 @@ public class WindowManagerShellCommand extends ShellCommand {
mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
mLetterboxConfiguration.resetIsReachabilityEnabled();
mLetterboxConfiguration.resetDefaultPositionForReachability();
mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
mLetterboxConfiguration.resetDefaultPositionForHorizontalReachability();
mLetterboxConfiguration.resetDefaultPositionForVerticalReachability();
mLetterboxConfiguration.resetIsEducationEnabled();
}
}
@@ -1044,11 +1143,16 @@ public class WindowManagerShellCommand extends ShellCommand {
+ mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier());
pw.println("Aspect ratio: "
+ mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
pw.println("Is reachability enabled: "
+ mLetterboxConfiguration.getIsReachabilityEnabled());
pw.println("Default position for reachability: "
+ LetterboxConfiguration.letterboxReachabilityPositionToString(
mLetterboxConfiguration.getDefaultPositionForReachability()));
pw.println("Is horizontal reachability enabled: "
+ mLetterboxConfiguration.getIsHorizontalReachabilityEnabled());
pw.println("Is vertical reachability enabled: "
+ mLetterboxConfiguration.getIsVerticalReachabilityEnabled());
pw.println("Default position for horizontal reachability: "
+ LetterboxConfiguration.letterboxHorizontalReachabilityPositionToString(
mLetterboxConfiguration.getDefaultPositionForHorizontalReachability()));
pw.println("Default position for vertical reachability: "
+ LetterboxConfiguration.letterboxVerticalReachabilityPositionToString(
mLetterboxConfiguration.getDefaultPositionForVerticalReachability()));
pw.println("Is education enabled: "
+ mLetterboxConfiguration.getIsEducationEnabled());
@@ -1185,18 +1289,30 @@ 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(" --defaultPositionForReachability [left|center|right]");
pw.println(" Default horizontal position of app window when reachability is.");
pw.println(" --verticalPositionMultiplier multiplier");
pw.println(" Vertical position of app window center. If multiplier < 0 or > 1,");
pw.println(" both it and R.dimen.config_letterboxVerticalPositionMultiplier");
pw.println(" are ignored and central position (0.5) is used.");
pw.println(" --isHorizontalReachabilityEnabled [true|1|false|0]");
pw.println(" Whether horizontal reachability repositioning is allowed for ");
pw.println(" letterboxed fullscreen apps in landscape device orientation.");
pw.println(" --isVerticalReachabilityEnabled [true|1|false|0]");
pw.println(" Whether vertical reachability repositioning is allowed for ");
pw.println(" letterboxed fullscreen apps in portrait device orientation.");
pw.println(" --defaultPositionForHorizontalReachability [left|center|right]");
pw.println(" Default position of app window when horizontal reachability is.");
pw.println(" enabled.");
pw.println(" --defaultPositionForVerticalReachability [top|center|bottom]");
pw.println(" Default position of app window when vertical reachability is.");
pw.println(" enabled.");
pw.println(" --isEducationEnabled [true|1|false|0]");
pw.println(" Whether education is allowed for letterboxed fullscreen apps.");
pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType");
pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
pw.println(" |horizontalPositionMultiplier|isReachabilityEnabled");
pw.println(" isEducationEnabled||defaultPositionMultiplierForReachability]");
pw.println(" |horizontalPositionMultiplier|verticalPositionMultiplier");
pw.println(" |isHorizontalReachabilityEnabled|isVerticalReachabilityEnabled");
pw.println(" isEducationEnabled||defaultPositionMultiplierForHorizontalReachability");
pw.println(" ||defaultPositionMultiplierForVerticalReachability]");
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.");

View File

@@ -63,7 +63,7 @@ public class LetterboxTest {
mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
() -> mAreCornersRounded, () -> Color.valueOf(mColor),
() -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha,
/* doubleTapCallback= */ x -> {});
/* doubleTapCallbackX= */ x -> {}, /* doubleTapCallbackY= */ y -> {});
mTransaction = spy(StubTransaction.class);
}

View File

@@ -1928,7 +1928,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED);
// Bounds are letterboxed to respect the provided max aspect ratio.
assertEquals(mActivity.getBounds(), new Rect(0, 0, 1000, 1100));
assertEquals(mActivity.getBounds(), new Rect(0, 850, 1000, 1950));
// Move activity to split screen which has landscape size.
mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents */ false, "test");
@@ -2045,19 +2045,14 @@ public class SizeCompatTests extends WindowTestsBase {
mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
letterboxHorizontalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
assertEquals(fixedOrientationLetterbox, mActivity.getBounds());
// Rotate to put activity in size compat mode.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
assertEquals(sizeCompatUnscaled, mActivity.getBounds());
// Force activity to scaled down for size compat mode.
resizeDisplay(mTask.mDisplayContent, 700, 1400);
assertTrue(mActivity.inSizeCompatMode());
assertScaled();
assertEquals(sizeCompatScaled, mActivity.getBounds());
@@ -2074,6 +2069,109 @@ public class SizeCompatTests extends WindowTestsBase {
/* letterboxHorizontalPositionMultiplier */ 1.0f);
}
@Test
public void testUpdateResolvedBoundsVerticalPosition_top() {
// Display configured as (1400, 2800).
assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
/* letterboxVerticalPositionMultiplier */ 0.0f,
// At launch.
/* fixedOrientationLetterbox */ new Rect(0, 0, 1400, 700),
// After 90 degree rotation.
/* sizeCompatUnscaled */ new Rect(700, 0, 2100, 700),
// After the display is resized to (1400, 700).
/* sizeCompatScaled */ new Rect(0, 0, 700, 350));
}
@Test
public void testUpdateResolvedBoundsVerticalPosition_center() {
// Display configured as (1400, 2800).
assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
/* letterboxVerticalPositionMultiplier */ 0.5f,
// At launch.
/* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
// After 90 degree rotation.
/* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
// After the display is resized to (1400, 700).
/* sizeCompatScaled */ new Rect(0, 525, 700, 875));
}
@Test
public void testUpdateResolvedBoundsVerticalPosition_invalidMultiplier_defaultToCenter() {
// Display configured as (1400, 2800).
// Below 0.0.
assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
/* letterboxVerticalPositionMultiplier */ -1.0f,
// At launch.
/* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
// After 90 degree rotation.
/* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
// After the display is resized to (1400, 700).
/* sizeCompatScaled */ new Rect(0, 525, 700, 875));
// Above 1.0
assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
/* letterboxVerticalPositionMultiplier */ 2.0f,
// At launch.
/* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750),
// After 90 degree rotation.
/* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050),
// After the display is resized to (1400, 700).
/* sizeCompatScaled */ new Rect(0, 525, 700, 875));
}
@Test
public void testUpdateResolvedBoundsVerticalPosition_bottom() {
// Display configured as (1400, 2800).
assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
/* letterboxVerticalPositionMultiplier */ 1.0f,
// At launch.
/* fixedOrientationLetterbox */ new Rect(0, 2100, 1400, 2800),
// After 90 degree rotation.
/* sizeCompatUnscaled */ new Rect(700, 700, 2100, 1400),
// After the display is resized to (1400, 700).
/* sizeCompatScaled */ new Rect(0, 1050, 700, 1400));
}
private void assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity(
float letterboxVerticalPositionMultiplier, Rect fixedOrientationLetterbox,
Rect sizeCompatUnscaled, Rect sizeCompatScaled) {
// Set up a display in portrait and ignoring orientation request.
setUpDisplaySizeWithApp(1400, 2800);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(
letterboxVerticalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
assertEquals(fixedOrientationLetterbox, mActivity.getBounds());
// Rotate to put activity in size compat mode.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
assertEquals(sizeCompatUnscaled, mActivity.getBounds());
// Force activity to scaled down for size compat mode.
resizeDisplay(mTask.mDisplayContent, 1400, 700);
assertTrue(mActivity.inSizeCompatMode());
assertScaled();
assertEquals(sizeCompatScaled, mActivity.getBounds());
}
@Test
public void testUpdateResolvedBoundsVerticalPosition_activityFillParentHeight() {
// When activity height equals parent height, multiplier shouldn't have any effect.
assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
/* letterboxVerticalPositionMultiplier */ 0.0f);
assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
/* letterboxVerticalPositionMultiplier */ 0.5f);
assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
/* letterboxVerticalPositionMultiplier */ 1.0f);
}
@Test
public void testAreBoundsLetterboxed_letterboxedForAspectRatio_returnsTrue() {
setUpDisplaySizeWithApp(1000, 2500);
@@ -2367,6 +2465,23 @@ public class SizeCompatTests extends WindowTestsBase {
mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
letterboxHorizontalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
assertFitted();
// Rotate to put activity in size compat mode.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
assertEquals(new Rect(0, 1050, 1400, 1750), mActivity.getBounds());
}
private void assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity(
float letterboxVerticalPositionMultiplier) {
// Set up a display in portrait and ignoring orientation request.
setUpDisplaySizeWithApp(1400, 2800);
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(
letterboxVerticalPositionMultiplier);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
assertFitted();
@@ -2375,7 +2490,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(mActivity.inSizeCompatMode());
// Activity is in size compat mode but not scaled.
assertEquals(new Rect(0, 1050, 1400, 1750), mActivity.getBounds());
assertEquals(new Rect(1050, 0, 1750, 1400), mActivity.getBounds());
}
private static WindowState addWindowToActivity(ActivityRecord activity) {

View File

@@ -229,14 +229,22 @@ class WindowTestsBase extends SystemServiceTestsBase {
// {@link com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}, is set
// on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(0);
// Ensure letterbox position multiplier is not overridden on any device target.
// Ensure letterbox horizontal position multiplier is not overridden on any device target.
// {@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},
// Ensure letterbox vertical position multiplier is not overridden on any device target.
// {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier},
// may be set on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setIsReachabilityEnabled(false);
mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
// Ensure letterbox horizontal reachability treatment isn't overridden on any device target.
// {@link com.android.internal.R.bool.config_letterboxIsHorizontalReachabilityEnabled},
// may be set on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(false);
// Ensure letterbox vertical reachability treatment isn't overridden on any device target.
// {@link com.android.internal.R.bool.config_letterboxIsVerticalReachabilityEnabled},
// may be set on some device form factors.
mAtm.mWindowManager.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(false);
checkDeviceSpecificOverridesNotApplied();
}
@@ -246,7 +254,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
// Revert back to device overrides.
mAtm.mWindowManager.mLetterboxConfiguration.resetFixedOrientationLetterboxAspectRatio();
mAtm.mWindowManager.mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
mAtm.mWindowManager.mLetterboxConfiguration.resetIsReachabilityEnabled();
mAtm.mWindowManager.mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
mAtm.mWindowManager.mLetterboxConfiguration.resetIsVerticalReachabilityEnabled();
}
/**