Merge "Letterboxing improvements for tabletop mode" into tm-qpr-dev am: 59326ce728

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20111697

Change-Id: I4006f2c9a1a88b530a6d79f83420d268365b6fa5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2060824..4ee8bc3c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5151,6 +5151,15 @@
          the format [System DeviceState]:[WM Jetpack Posture], for example: "0:1". -->
     <string-array name="config_device_state_postures" translatable="false" />
 
+    <!-- Which Surface rotations are considered as tabletop posture (horizontal hinge) when the
+         device is half-folded. Other half-folded postures will be assumed to be book (vertical
+         hinge) mode. Units: degrees; valid values: 0, 90, 180, 270. -->
+    <integer-array name="config_deviceTabletopRotations" />
+
+    <!-- This flag indicates that a display with fold-state FLAT should always be considered as
+         having a separating hinge. -->
+    <bool name="config_isDisplayHingeAlwaysSeparating">false</bool>
+
     <!-- Aspect ratio of letterboxing for fixed orientation. Values <= 1.0 will be ignored.
          Note: Activity min/max aspect ratio restrictions will still be respected.
          Therefore this override can control the maximum screen area that can be occupied by
@@ -5199,14 +5208,26 @@
 
     <!-- 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 position is used (0.5). -->
+        or > 1 it is ignored and for non-book mode central position is used (0.5); for book mode
+         left is used (0.0). -->
     <item name="config_letterboxHorizontalPositionMultiplier" format="float" type="dimen">0.5</item>
 
     <!-- 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). -->
+        or > 1 it is ignored and for non-tabletop mode central position is used (0.5); for
+         tabletop mode top (0.0) is used. -->
     <item name="config_letterboxVerticalPositionMultiplier" format="float" type="dimen">0.0</item>
 
+    <!-- Horizontal position of a center of the letterboxed app window when in book mode.
+    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 left position is used (0.0). -->
+    <item name="config_letterboxBookModePositionMultiplier" format="float" type="dimen">0.0</item>
+
+    <!-- Vertical position of a center of the letterboxed app window when in tabletop mode.
+        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 top position is used (0.0). -->
+    <item name="config_letterboxTabletopModePositionMultiplier" format="float" type="dimen">0.0</item>
+
     <!-- Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps.
     -->
     <bool name="config_letterboxIsHorizontalReachabilityEnabled">false</bool>
@@ -5234,6 +5255,26 @@
         If given value is outside of this range, the option 1 (center) is assummed. -->
     <integer name="config_letterboxDefaultPositionForVerticalReachability">1</integer>
 
+    <!-- Default horizontal position of the letterboxed app window when reachability is
+    enabled and an app is fullscreen in landscape device orientation and in book mode. When
+    reachability is enabled, the position can change between left, center and right. This config
+    defines the default one:
+        - Option 0 - Left.
+        - Option 1 - Center.
+        - Option 2 - Right.
+    If given value is outside of this range, the option 0 (left) is assummed. -->
+    <integer name="config_letterboxDefaultPositionForBookModeReachability">0</integer>
+
+    <!-- Default vertical position of the letterboxed app window when reachability is
+        enabled and an app is fullscreen in portrait device orientation and in tabletop mode. 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 0 (top) is assummed. -->
+    <integer name="config_letterboxDefaultPositionForTabletopModeReachability">0</integer>
+
     <!-- Whether displaying letterbox education is enabled for letterboxed fullscreen apps. -->
     <bool name="config_letterboxIsEducationEnabled">false</bool>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2b67d64..58c4e5e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4459,6 +4459,8 @@
   <java-symbol type="array" name="config_keep_warming_services" />
   <java-symbol type="string" name="config_display_features" />
   <java-symbol type="array" name="config_device_state_postures" />
+  <java-symbol type="array" name="config_deviceTabletopRotations" />
+  <java-symbol type="bool" name="config_isDisplayHingeAlwaysSeparating" />
 
   <java-symbol type="dimen" name="controls_thumbnail_image_max_height" />
   <java-symbol type="dimen" name="controls_thumbnail_image_max_width" />
@@ -4471,10 +4473,14 @@
   <java-symbol type="color" name="config_letterboxBackgroundColor" />
   <java-symbol type="dimen" name="config_letterboxHorizontalPositionMultiplier" />
   <java-symbol type="dimen" name="config_letterboxVerticalPositionMultiplier" />
+  <java-symbol type="dimen" name="config_letterboxBookModePositionMultiplier" />
+  <java-symbol type="dimen" name="config_letterboxTabletopModePositionMultiplier" />
   <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="integer" name="config_letterboxDefaultPositionForBookModeReachability" />
+  <java-symbol type="integer" name="config_letterboxDefaultPositionForTabletopModeReachability" />
   <java-symbol type="bool" name="config_letterboxIsEducationEnabled" />
   <java-symbol type="dimen" name="config_letterboxDefaultMinAspectRatioForUnresizableApps" />
   <java-symbol type="bool" name="config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled" />
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 86c8097..49704d9 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1525,6 +1525,12 @@
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "-637815408": {
+      "message": "Invalid surface rotation angle in config_deviceTabletopRotations: %d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
     "-636553602": {
       "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
       "level": "VERBOSE",
@@ -3193,6 +3199,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/TaskFragment.java"
     },
+    "939638078": {
+      "message": "config_deviceTabletopRotations is not defined. Half-fold letterboxing will work inconsistently.",
+      "level": "WARN",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
     "948208142": {
       "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
       "level": "DEBUG",
diff --git a/proto/src/windowmanager.proto b/proto/src/windowmanager.proto
index f26404c6..da4dfa9 100644
--- a/proto/src/windowmanager.proto
+++ b/proto/src/windowmanager.proto
@@ -68,4 +68,8 @@
   LetterboxHorizontalReachability letterbox_position_for_horizontal_reachability = 1;
   // Represents the current vertical position for the letterboxed activity
   LetterboxVerticalReachability letterbox_position_for_vertical_reachability = 2;
+  // Represents the current horizontal position for the letterboxed activity in book mode
+  LetterboxHorizontalReachability letterbox_position_for_book_mode_reachability = 3;
+  // Represents the current vertical position for the letterboxed activity in tabletop mode
+  LetterboxVerticalReachability letterbox_position_for_tabletop_mode_reachability = 4;
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 418e1ed..57eeb9a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -8149,7 +8149,7 @@
     }
 
     /**
-     * Adjusts position of resolved bounds if they doesn't fill the parent using gravity
+     * Adjusts position of resolved bounds if they don't fill the parent using gravity
      * requested in the config or via an ADB command. For more context see {@link
      * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and
      * {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)}
@@ -8168,9 +8168,8 @@
         int offsetX = 0;
         if (parentBounds.width() != screenResolvedBounds.width()) {
             if (screenResolvedBounds.width() <= parentAppBounds.width()) {
-                float positionMultiplier =
-                        mLetterboxUiController.getHorizontalPositionMultiplier(
-                                newParentConfiguration);
+                float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier(
+                        newParentConfiguration);
                 offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
                         * positionMultiplier);
             }
@@ -8180,9 +8179,8 @@
         int offsetY = 0;
         if (parentBounds.height() != screenResolvedBounds.height()) {
             if (screenResolvedBounds.height() <= parentAppBounds.height()) {
-                float positionMultiplier =
-                        mLetterboxUiController.getVerticalPositionMultiplier(
-                                newParentConfiguration);
+                float positionMultiplier = mLetterboxUiController.getVerticalPositionMultiplier(
+                        newParentConfiguration);
                 offsetY = (int) Math.ceil((parentAppBounds.height() - screenResolvedBounds.height())
                         * positionMultiplier);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 4fb137b..34bdb7a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.util.RotationUtils.deltaRotation;
@@ -55,6 +56,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -76,6 +78,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayDeque;
+import java.util.Set;
 
 /**
  * Defines the mapping between orientation and rotation of a display.
@@ -1552,6 +1555,15 @@
         proto.end(token);
     }
 
+    boolean isDeviceInPosture(DeviceStateController.FoldState state, boolean isTabletop) {
+        if (mFoldController == null) return false;
+        return mFoldController.isDeviceInPosture(state, isTabletop);
+    }
+
+    boolean isDisplaySeparatingHinge() {
+        return mFoldController != null && mFoldController.isSeparatingHinge();
+    }
+
     /**
      * Called by the DeviceStateManager callback when the device state changes.
      */
@@ -1569,6 +1581,63 @@
         private DeviceStateController.FoldState mFoldState =
                 DeviceStateController.FoldState.UNKNOWN;
         private boolean mInHalfFoldTransition = false;
+        private final boolean mIsDisplayAlwaysSeparatingHinge;
+        private final Set<Integer> mTabletopRotations;
+
+        FoldController() {
+            mTabletopRotations = new ArraySet<>();
+            int[] tabletop_rotations = mContext.getResources().getIntArray(
+                    R.array.config_deviceTabletopRotations);
+            if (tabletop_rotations != null) {
+                for (int angle : tabletop_rotations) {
+                    switch (angle) {
+                        case 0:
+                            mTabletopRotations.add(Surface.ROTATION_0);
+                            break;
+                        case 90:
+                            mTabletopRotations.add(Surface.ROTATION_90);
+                            break;
+                        case 180:
+                            mTabletopRotations.add(Surface.ROTATION_180);
+                            break;
+                        case 270:
+                            mTabletopRotations.add(Surface.ROTATION_270);
+                            break;
+                        default:
+                            ProtoLog.e(WM_DEBUG_ORIENTATION,
+                                    "Invalid surface rotation angle in "
+                                            + "config_deviceTabletopRotations: %d",
+                                    angle);
+                    }
+                }
+            } else {
+                ProtoLog.w(WM_DEBUG_ORIENTATION,
+                        "config_deviceTabletopRotations is not defined. Half-fold "
+                                + "letterboxing will work inconsistently.");
+            }
+            mIsDisplayAlwaysSeparatingHinge = mContext.getResources().getBoolean(
+                    R.bool.config_isDisplayHingeAlwaysSeparating);
+        }
+
+        boolean isDeviceInPosture(DeviceStateController.FoldState state, boolean isTabletop) {
+            if (state != mFoldState) {
+                return false;
+            }
+            if (mFoldState == DeviceStateController.FoldState.HALF_FOLDED) {
+                return !(isTabletop ^ mTabletopRotations.contains(mRotation));
+            }
+            return true;
+        }
+
+        DeviceStateController.FoldState getFoldState() {
+            return mFoldState;
+        }
+
+        boolean isSeparatingHinge() {
+            return mFoldState == DeviceStateController.FoldState.HALF_FOLDED
+                    || (mFoldState == DeviceStateController.FoldState.OPEN
+                        && mIsDisplayAlwaysSeparatingHinge);
+        }
 
         boolean overrideFrozenRotation() {
             return mFoldState == DeviceStateController.FoldState.HALF_FOLDED;
@@ -1617,6 +1686,15 @@
                 mService.updateRotation(false /* alwaysSendConfiguration */,
                         false /* forceRelayout */);
             }
+            // Alert the activity of possible new bounds.
+            final Task topFullscreenTask =
+                    mDisplayContent.getTask(t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
+            if (topFullscreenTask != null) {
+                final ActivityRecord top = topFullscreenTask.topRunningActivity();
+                if (top != null) {
+                    top.recomputeConfiguration();
+                }
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 127a7bf..3eca364 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -16,12 +16,16 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Color;
 import android.provider.DeviceConfig;
+import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -33,6 +37,8 @@
 /** Reads letterbox configs from resources and controls their overrides at runtime. */
 final class LetterboxConfiguration {
 
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxConfiguration" : TAG_ATM;
+
     /**
      * Override of aspect ratio for fixed orientation letterboxing that is set via ADB with
      * set-fixed-orientation-letterbox-aspect-ratio or via {@link
@@ -144,6 +150,14 @@
     // side of the screen and 1.0 to the bottom side.
     private float mLetterboxVerticalPositionMultiplier;
 
+    // Horizontal position of a center of the letterboxed app window when the device is half-folded.
+    // 0 corresponds to the left side of the screen and 1.0 to the right side.
+    private float mLetterboxBookModePositionMultiplier;
+
+    // Vertical position of a center of the letterboxed app window when the device is half-folded.
+    // 0 corresponds to the top side of the screen and 1.0 to the bottom side.
+    private float mLetterboxTabletopModePositionMultiplier;
+
     // 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.
@@ -179,8 +193,15 @@
 
     LetterboxConfiguration(Context systemUiContext) {
         this(systemUiContext, new LetterboxConfigurationPersister(systemUiContext,
-                () -> readLetterboxHorizontalReachabilityPositionFromConfig(systemUiContext),
-                () -> readLetterboxVerticalReachabilityPositionFromConfig(systemUiContext)));
+                () -> readLetterboxHorizontalReachabilityPositionFromConfig(systemUiContext,
+                        /* forBookMode */ false),
+                () -> readLetterboxVerticalReachabilityPositionFromConfig(systemUiContext,
+                        /* forTabletopMode */ false),
+                () -> readLetterboxHorizontalReachabilityPositionFromConfig(systemUiContext,
+                        /* forBookMode */ true),
+                () -> readLetterboxVerticalReachabilityPositionFromConfig(systemUiContext,
+                        /* forTabletopMode */ true)
+        ));
     }
 
     @VisibleForTesting
@@ -200,14 +221,18 @@
                 R.dimen.config_letterboxHorizontalPositionMultiplier);
         mLetterboxVerticalPositionMultiplier = mContext.getResources().getFloat(
                 R.dimen.config_letterboxVerticalPositionMultiplier);
+        mLetterboxBookModePositionMultiplier = mContext.getResources().getFloat(
+                R.dimen.config_letterboxBookModePositionMultiplier);
+        mLetterboxTabletopModePositionMultiplier = mContext.getResources().getFloat(
+                R.dimen.config_letterboxTabletopModePositionMultiplier);
         mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean(
                 R.bool.config_letterboxIsHorizontalReachabilityEnabled);
         mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean(
                 R.bool.config_letterboxIsVerticalReachabilityEnabled);
         mDefaultPositionForHorizontalReachability =
-                readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
+                readLetterboxHorizontalReachabilityPositionFromConfig(mContext, false);
         mDefaultPositionForVerticalReachability =
-                readLetterboxVerticalReachabilityPositionFromConfig(mContext);
+                readLetterboxVerticalReachabilityPositionFromConfig(mContext, false);
         mIsEducationEnabled = mContext.getResources().getBoolean(
                 R.bool.config_letterboxIsEducationEnabled);
         setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat(
@@ -460,11 +485,30 @@
      * or via an ADB command. 0 corresponds to the left side of the screen and 1 to the
      * right side.
      */
-    float getLetterboxHorizontalPositionMultiplier() {
-        return (mLetterboxHorizontalPositionMultiplier < 0.0f
-                || mLetterboxHorizontalPositionMultiplier > 1.0f)
-                        // Default to central position if invalid value is provided.
-                        ? 0.5f : mLetterboxHorizontalPositionMultiplier;
+    float getLetterboxHorizontalPositionMultiplier(boolean isInBookMode) {
+        if (isInBookMode) {
+            if (mLetterboxBookModePositionMultiplier < 0.0f
+                    || mLetterboxBookModePositionMultiplier > 1.0f) {
+                Slog.w(TAG,
+                        "mLetterboxBookModePositionMultiplier out of bounds (isInBookMode=true): "
+                        + mLetterboxBookModePositionMultiplier);
+                // Default to left position if invalid value is provided.
+                return 0.0f;
+            } else {
+                return mLetterboxBookModePositionMultiplier;
+            }
+        } else {
+            if (mLetterboxHorizontalPositionMultiplier < 0.0f
+                    || mLetterboxHorizontalPositionMultiplier > 1.0f) {
+                Slog.w(TAG,
+                        "mLetterboxBookModePositionMultiplier out of bounds (isInBookMode=false):"
+                        + mLetterboxBookModePositionMultiplier);
+                // Default to central position if invalid value is provided.
+                return 0.5f;
+            } else {
+                return mLetterboxHorizontalPositionMultiplier;
+            }
+        }
     }
 
     /*
@@ -473,11 +517,18 @@
      * 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;
+    float getLetterboxVerticalPositionMultiplier(boolean isInTabletopMode) {
+        if (isInTabletopMode) {
+            return (mLetterboxTabletopModePositionMultiplier < 0.0f
+                    || mLetterboxTabletopModePositionMultiplier > 1.0f)
+                    // Default to top position if invalid value is provided.
+                    ? 0.0f : mLetterboxTabletopModePositionMultiplier;
+        } else {
+            return (mLetterboxVerticalPositionMultiplier < 0.0f
+                    || mLetterboxVerticalPositionMultiplier > 1.0f)
+                    // Default to central position if invalid value is provided.
+                    ? 0.5f : mLetterboxVerticalPositionMultiplier;
+        }
     }
 
     /**
@@ -618,7 +669,8 @@
      */
     void resetDefaultPositionForHorizontalReachability() {
         mDefaultPositionForHorizontalReachability =
-                readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
+                readLetterboxHorizontalReachabilityPositionFromConfig(mContext,
+                        false /* forBookMode */);
     }
 
     /**
@@ -627,27 +679,34 @@
      */
     void resetDefaultPositionForVerticalReachability() {
         mDefaultPositionForVerticalReachability =
-                readLetterboxVerticalReachabilityPositionFromConfig(mContext);
+                readLetterboxVerticalReachabilityPositionFromConfig(mContext,
+                        false /* forTabletopMode */);
     }
 
     @LetterboxHorizontalReachabilityPosition
-    private static int readLetterboxHorizontalReachabilityPositionFromConfig(Context context) {
+    private static int readLetterboxHorizontalReachabilityPositionFromConfig(Context context,
+            boolean forBookMode) {
         int position = context.getResources().getInteger(
-                R.integer.config_letterboxDefaultPositionForHorizontalReachability);
+                forBookMode
+                    ? R.integer.config_letterboxDefaultPositionForBookModeReachability
+                    : 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
+                || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT
                     ? position : LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
     }
 
     @LetterboxVerticalReachabilityPosition
-    private static int readLetterboxVerticalReachabilityPositionFromConfig(Context context) {
+    private static int readLetterboxVerticalReachabilityPositionFromConfig(Context context,
+            boolean forTabletopMode) {
         int position = context.getResources().getInteger(
-                R.integer.config_letterboxDefaultPositionForVerticalReachability);
+                forTabletopMode
+                    ? R.integer.config_letterboxDefaultPositionForTabletopModeReachability
+                    : 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;
+                    ? position : LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
     }
 
     /*
@@ -656,9 +715,10 @@
      *
      * <p>The position multiplier is changed after each double tap in the letterbox area.
      */
-    float getHorizontalMultiplierForReachability() {
+    float getHorizontalMultiplierForReachability(boolean isDeviceInBookMode) {
         final int letterboxPositionForHorizontalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability(
+                        isDeviceInBookMode);
         switch (letterboxPositionForHorizontalReachability) {
             case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
                 return 0.0f;
@@ -679,9 +739,10 @@
      *
      * <p>The position multiplier is changed after each double tap in the letterbox area.
      */
-    float getVerticalMultiplierForReachability() {
+    float getVerticalMultiplierForReachability(boolean isDeviceInTabletopMode) {
         final int letterboxPositionForVerticalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(
+                        isDeviceInTabletopMode);
         switch (letterboxPositionForVerticalReachability) {
             case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
                 return 0.0f;
@@ -701,8 +762,9 @@
      * enabled.
      */
     @LetterboxHorizontalReachabilityPosition
-    int getLetterboxPositionForHorizontalReachability() {
-        return mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
+    int getLetterboxPositionForHorizontalReachability(boolean isInFullScreenBookMode) {
+        return mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability(
+                isInFullScreenBookMode);
     }
 
     /*
@@ -710,8 +772,9 @@
      * enabled.
      */
     @LetterboxVerticalReachabilityPosition
-    int getLetterboxPositionForVerticalReachability() {
-        return mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
+    int getLetterboxPositionForVerticalReachability(boolean isInFullScreenTabletopMode) {
+        return mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(
+                isInFullScreenTabletopMode);
     }
 
     /** Returns a string representing the given {@link LetterboxHorizontalReachabilityPosition}. */
@@ -750,34 +813,41 @@
      * Changes letterbox position for horizontal reachability to the next available one on the
      * right side.
      */
-    void movePositionForHorizontalReachabilityToNextRightStop() {
-        updatePositionForHorizontalReachability(prev -> Math.min(
-                prev + 1, LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT));
+    void movePositionForHorizontalReachabilityToNextRightStop(boolean isDeviceInBookMode) {
+        updatePositionForHorizontalReachability(isDeviceInBookMode, prev -> Math.min(
+                prev + (isDeviceInBookMode ? 2 : 1), // Move 2 stops in book mode to avoid center.
+                LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT));
     }
 
     /**
      * Changes letterbox position for horizontal reachability to the next available one on the left
      * side.
      */
-    void movePositionForHorizontalReachabilityToNextLeftStop() {
-        updatePositionForHorizontalReachability(prev -> Math.max(prev - 1, 0));
+    void movePositionForHorizontalReachabilityToNextLeftStop(boolean isDeviceInBookMode) {
+        updatePositionForHorizontalReachability(isDeviceInBookMode, prev -> Math.max(
+                prev - (isDeviceInBookMode ? 2 : 1), 0)); // Move 2 stops in book mode to avoid
+                                                          // center.
     }
 
     /**
      * Changes letterbox position for vertical reachability to the next available one on the bottom
      * side.
      */
-    void movePositionForVerticalReachabilityToNextBottomStop() {
-        updatePositionForVerticalReachability(prev -> Math.min(
-                prev + 1, LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM));
+    void movePositionForVerticalReachabilityToNextBottomStop(boolean isDeviceInTabletopMode) {
+        updatePositionForVerticalReachability(isDeviceInTabletopMode, prev -> Math.min(
+                prev + (isDeviceInTabletopMode ? 2 : 1), // Move 2 stops in tabletop mode to avoid
+                                                         // center.
+                LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM));
     }
 
     /**
      * Changes letterbox position for vertical reachability to the next available one on the top
      * side.
      */
-    void movePositionForVerticalReachabilityToNextTopStop() {
-        updatePositionForVerticalReachability(prev -> Math.max(prev - 1, 0));
+    void movePositionForVerticalReachabilityToNextTopStop(boolean isDeviceInTabletopMode) {
+        updatePositionForVerticalReachability(isDeviceInTabletopMode, prev -> Math.max(
+                prev - (isDeviceInTabletopMode ? 2 : 1), 0)); // Move 2 stops in tabletop mode to
+                                                              // avoid center.
     }
 
     /**
@@ -854,25 +924,27 @@
     }
 
     /** Calculates a new letterboxPositionForHorizontalReachability value and updates the store */
-    private void updatePositionForHorizontalReachability(
+    private void updatePositionForHorizontalReachability(boolean isDeviceInBookMode,
             Function<Integer, Integer> newHorizonalPositionFun) {
         final int letterboxPositionForHorizontalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability(
+                        isDeviceInBookMode);
         final int nextHorizontalPosition = newHorizonalPositionFun.apply(
                 letterboxPositionForHorizontalReachability);
         mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
-                nextHorizontalPosition);
+                isDeviceInBookMode, nextHorizontalPosition);
     }
 
     /** Calculates a new letterboxPositionForVerticalReachability value and updates the store */
-    private void updatePositionForVerticalReachability(
+    private void updatePositionForVerticalReachability(boolean isDeviceInTabletopMode,
             Function<Integer, Integer> newVerticalPositionFun) {
         final int letterboxPositionForVerticalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(
+                        isDeviceInTabletopMode);
         final int nextVerticalPosition = newVerticalPositionFun.apply(
                 letterboxPositionForVerticalReachability);
         mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
-                nextVerticalPosition);
+                isDeviceInTabletopMode, nextVerticalPosition);
     }
 
     // TODO(b/262378106): Cache runtime flag and implement DeviceConfig.OnPropertiesChangedListener
diff --git a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
index 70639b1..4a99db5 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java
@@ -55,6 +55,8 @@
     private final Context mContext;
     private final Supplier<Integer> mDefaultHorizontalReachabilitySupplier;
     private final Supplier<Integer> mDefaultVerticalReachabilitySupplier;
+    private final Supplier<Integer> mDefaultBookModeReachabilitySupplier;
+    private final Supplier<Integer> mDefaultTabletopModeReachabilitySupplier;
 
     // 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
@@ -64,6 +66,11 @@
     @LetterboxHorizontalReachabilityPosition
     private volatile int mLetterboxPositionForHorizontalReachability;
 
+    // The same as mLetterboxPositionForHorizontalReachability but used when the device is
+    // half-folded.
+    @LetterboxHorizontalReachabilityPosition
+    private volatile int mLetterboxPositionForBookModeReachability;
+
     // 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
@@ -72,6 +79,11 @@
     @LetterboxVerticalReachabilityPosition
     private volatile int mLetterboxPositionForVerticalReachability;
 
+    // The same as mLetterboxPositionForVerticalReachability but used when the device is
+    // half-folded.
+    @LetterboxVerticalReachabilityPosition
+    private volatile int mLetterboxPositionForTabletopModeReachability;
+
     @NonNull
     private final AtomicFile mConfigurationFile;
 
@@ -83,9 +95,13 @@
 
     LetterboxConfigurationPersister(Context systemUiContext,
             Supplier<Integer> defaultHorizontalReachabilitySupplier,
-            Supplier<Integer> defaultVerticalReachabilitySupplier) {
+            Supplier<Integer> defaultVerticalReachabilitySupplier,
+            Supplier<Integer> defaultBookModeReachabilitySupplier,
+            Supplier<Integer> defaultTabletopModeReachabilitySupplier) {
         this(systemUiContext, defaultHorizontalReachabilitySupplier,
                 defaultVerticalReachabilitySupplier,
+                defaultBookModeReachabilitySupplier,
+                defaultTabletopModeReachabilitySupplier,
                 Environment.getDataSystemDirectory(), new PersisterQueue(),
                 /* completionCallback */ null);
     }
@@ -93,11 +109,18 @@
     @VisibleForTesting
     LetterboxConfigurationPersister(Context systemUiContext,
             Supplier<Integer> defaultHorizontalReachabilitySupplier,
-            Supplier<Integer> defaultVerticalReachabilitySupplier, File configFolder,
+            Supplier<Integer> defaultVerticalReachabilitySupplier,
+            Supplier<Integer> defaultBookModeReachabilitySupplier,
+            Supplier<Integer> defaultTabletopModeReachabilitySupplier,
+            File configFolder,
             PersisterQueue persisterQueue, @Nullable Consumer<String> completionCallback) {
         mContext = systemUiContext.createDeviceProtectedStorageContext();
         mDefaultHorizontalReachabilitySupplier = defaultHorizontalReachabilitySupplier;
         mDefaultVerticalReachabilitySupplier = defaultVerticalReachabilitySupplier;
+        mDefaultBookModeReachabilitySupplier =
+                defaultBookModeReachabilitySupplier;
+        mDefaultTabletopModeReachabilitySupplier =
+                defaultTabletopModeReachabilitySupplier;
         mCompletionCallback = completionCallback;
         final File prefFiles = new File(configFolder, LETTERBOX_CONFIGURATION_FILENAME);
         mConfigurationFile = new AtomicFile(prefFiles);
@@ -117,8 +140,12 @@
      * enabled.
      */
     @LetterboxHorizontalReachabilityPosition
-    int getLetterboxPositionForHorizontalReachability() {
-        return mLetterboxPositionForHorizontalReachability;
+    int getLetterboxPositionForHorizontalReachability(boolean forBookMode) {
+        if (forBookMode) {
+            return mLetterboxPositionForBookModeReachability;
+        } else {
+            return mLetterboxPositionForHorizontalReachability;
+        }
     }
 
     /*
@@ -126,31 +153,55 @@
      * enabled.
      */
     @LetterboxVerticalReachabilityPosition
-    int getLetterboxPositionForVerticalReachability() {
-        return mLetterboxPositionForVerticalReachability;
-    }
-
-    /**
-     * Updates letterboxPositionForVerticalReachability if different from the current value
-     */
-    void setLetterboxPositionForHorizontalReachability(
-            int letterboxPositionForHorizontalReachability) {
-        if (mLetterboxPositionForHorizontalReachability
-                != letterboxPositionForHorizontalReachability) {
-            mLetterboxPositionForHorizontalReachability =
-                    letterboxPositionForHorizontalReachability;
-            updateConfiguration();
+    int getLetterboxPositionForVerticalReachability(boolean forTabletopMode) {
+        if (forTabletopMode) {
+            return mLetterboxPositionForTabletopModeReachability;
+        } else {
+            return mLetterboxPositionForVerticalReachability;
         }
     }
 
     /**
      * Updates letterboxPositionForVerticalReachability if different from the current value
      */
-    void setLetterboxPositionForVerticalReachability(
+    void setLetterboxPositionForHorizontalReachability(boolean forBookMode,
+            int letterboxPositionForHorizontalReachability) {
+        if (forBookMode) {
+            if (mLetterboxPositionForBookModeReachability
+                    != letterboxPositionForHorizontalReachability) {
+                mLetterboxPositionForBookModeReachability =
+                        letterboxPositionForHorizontalReachability;
+                updateConfiguration();
+            }
+        } else {
+            if (mLetterboxPositionForHorizontalReachability
+                    != letterboxPositionForHorizontalReachability) {
+                mLetterboxPositionForHorizontalReachability =
+                        letterboxPositionForHorizontalReachability;
+                updateConfiguration();
+            }
+        }
+    }
+
+    /**
+     * Updates letterboxPositionForVerticalReachability if different from the current value
+     */
+    void setLetterboxPositionForVerticalReachability(boolean forTabletopMode,
             int letterboxPositionForVerticalReachability) {
-        if (mLetterboxPositionForVerticalReachability != letterboxPositionForVerticalReachability) {
-            mLetterboxPositionForVerticalReachability = letterboxPositionForVerticalReachability;
-            updateConfiguration();
+        if (forTabletopMode) {
+            if (mLetterboxPositionForTabletopModeReachability
+                    != letterboxPositionForVerticalReachability) {
+                mLetterboxPositionForTabletopModeReachability =
+                        letterboxPositionForVerticalReachability;
+                updateConfiguration();
+            }
+        } else {
+            if (mLetterboxPositionForVerticalReachability
+                    != letterboxPositionForVerticalReachability) {
+                mLetterboxPositionForVerticalReachability =
+                        letterboxPositionForVerticalReachability;
+                updateConfiguration();
+            }
         }
     }
 
@@ -158,6 +209,10 @@
     void useDefaultValue() {
         mLetterboxPositionForHorizontalReachability = mDefaultHorizontalReachabilitySupplier.get();
         mLetterboxPositionForVerticalReachability = mDefaultVerticalReachabilitySupplier.get();
+        mLetterboxPositionForBookModeReachability =
+                mDefaultBookModeReachabilitySupplier.get();
+        mLetterboxPositionForTabletopModeReachability =
+                mDefaultTabletopModeReachabilitySupplier.get();
     }
 
     private void readCurrentConfiguration() {
@@ -171,6 +226,10 @@
                     letterboxData.letterboxPositionForHorizontalReachability;
             mLetterboxPositionForVerticalReachability =
                     letterboxData.letterboxPositionForVerticalReachability;
+            mLetterboxPositionForBookModeReachability =
+                    letterboxData.letterboxPositionForBookModeReachability;
+            mLetterboxPositionForTabletopModeReachability =
+                    letterboxData.letterboxPositionForTabletopModeReachability;
         } catch (IOException ioe) {
             Slog.e(TAG,
                     "Error reading from LetterboxConfigurationPersister. "
@@ -192,6 +251,8 @@
         mPersisterQueue.addItem(new UpdateValuesCommand(mConfigurationFile,
                 mLetterboxPositionForHorizontalReachability,
                 mLetterboxPositionForVerticalReachability,
+                mLetterboxPositionForBookModeReachability,
+                mLetterboxPositionForTabletopModeReachability,
                 mCompletionCallback), /* flush */ true);
     }
 
@@ -221,13 +282,18 @@
 
         private final int mHorizontalReachability;
         private final int mVerticalReachability;
+        private final int mBookModeReachability;
+        private final int mTabletopModeReachability;
 
         UpdateValuesCommand(@NonNull AtomicFile fileToUpdate,
                 int horizontalReachability, int verticalReachability,
+                int bookModeReachability, int tabletopModeReachability,
                 @Nullable Consumer<String> onComplete) {
             mFileToUpdate = fileToUpdate;
             mHorizontalReachability = horizontalReachability;
             mVerticalReachability = verticalReachability;
+            mBookModeReachability = bookModeReachability;
+            mTabletopModeReachability = tabletopModeReachability;
             mOnComplete = onComplete;
         }
 
@@ -237,6 +303,10 @@
                     new WindowManagerProtos.LetterboxProto();
             letterboxData.letterboxPositionForHorizontalReachability = mHorizontalReachability;
             letterboxData.letterboxPositionForVerticalReachability = mVerticalReachability;
+            letterboxData.letterboxPositionForBookModeReachability =
+                    mBookModeReachability;
+            letterboxData.letterboxPositionForTabletopModeReachability =
+                    mTabletopModeReachability;
             final byte[] bytes = WindowManagerProtos.LetterboxProto.toByteArray(letterboxData);
 
             FileOutputStream fos = null;
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index a53a5fc..9cb94c6 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -275,30 +275,62 @@
                 && mActivityRecord.fillsParent();
     }
 
+    // Check if we are in the given pose and in fullscreen mode.
+    // Note that we check the task rather than the parent as with ActivityEmbedding the parent might
+    // be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is
+    // actually fullscreen.
+    private boolean isDisplayFullScreenAndInPosture(DeviceStateController.FoldState state,
+            boolean isTabletop) {
+        Task task = mActivityRecord.getTask();
+        return mActivityRecord.mDisplayContent != null
+                && mActivityRecord.mDisplayContent.getDisplayRotation().isDeviceInPosture(state,
+                    isTabletop)
+                && task != null
+                && task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+    }
+
+    // Note that we check the task rather than the parent as with ActivityEmbedding the parent might
+    // be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is
+    // actually fullscreen.
+    private boolean isDisplayFullScreenAndSeparatingHinge() {
+        Task task = mActivityRecord.getTask();
+        return mActivityRecord.mDisplayContent != null
+                && mActivityRecord.mDisplayContent.getDisplayRotation().isDisplaySeparatingHinge()
+                && task != null
+                && task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+    }
+
+
     float getHorizontalPositionMultiplier(Configuration parentConfiguration) {
         // Don't check resolved configuration because it may not be updated yet during
         // configuration change.
+        boolean bookMode = isDisplayFullScreenAndInPosture(
+                DeviceStateController.FoldState.HALF_FOLDED, false /* isTabletop */);
         return isHorizontalReachabilityEnabled(parentConfiguration)
                 // Using the last global dynamic position to avoid "jumps" when moving
                 // between apps or activities.
-                ? mLetterboxConfiguration.getHorizontalMultiplierForReachability()
-                : mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier();
+                ? mLetterboxConfiguration.getHorizontalMultiplierForReachability(bookMode)
+                : mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(bookMode);
     }
 
     float getVerticalPositionMultiplier(Configuration parentConfiguration) {
         // Don't check resolved configuration because it may not be updated yet during
         // configuration change.
+        boolean tabletopMode = isDisplayFullScreenAndInPosture(
+                DeviceStateController.FoldState.HALF_FOLDED, true /* isTabletop */);
         return isVerticalReachabilityEnabled(parentConfiguration)
                 // Using the last global dynamic position to avoid "jumps" when moving
                 // between apps or activities.
-                ? mLetterboxConfiguration.getVerticalMultiplierForReachability()
-                : mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier();
+                ? mLetterboxConfiguration.getVerticalMultiplierForReachability(tabletopMode)
+                : mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier(tabletopMode);
     }
 
     float getFixedOrientationLetterboxAspectRatio() {
-        return mActivityRecord.shouldCreateCompatDisplayInsets()
-                ? getDefaultMinAspectRatioForUnresizableApps()
-                : mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
+        return isDisplayFullScreenAndSeparatingHinge()
+                ? getSplitScreenAspectRatio()
+                : mActivityRecord.shouldCreateCompatDisplayInsets()
+                    ? getDefaultMinAspectRatioForUnresizableApps()
+                    : mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
     }
 
     private float getDefaultMinAspectRatioForUnresizableApps() {
@@ -351,11 +383,13 @@
             return;
         }
 
+        boolean isInFullScreenBookMode = isDisplayFullScreenAndSeparatingHinge();
         int letterboxPositionForHorizontalReachability = mLetterboxConfiguration
-                .getLetterboxPositionForHorizontalReachability();
+                .getLetterboxPositionForHorizontalReachability(isInFullScreenBookMode);
         if (mLetterbox.getInnerFrame().left > x) {
             // Moving to the next stop on the left side of the app window: right > center > left.
-            mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextLeftStop();
+            mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextLeftStop(
+                    isInFullScreenBookMode);
             int changeToLog =
                     letterboxPositionForHorizontalReachability
                             == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER
@@ -364,7 +398,8 @@
             logLetterboxPositionChange(changeToLog);
         } else if (mLetterbox.getInnerFrame().right < x) {
             // Moving to the next stop on the right side of the app window: left > center > right.
-            mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop();
+            mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop(
+                    isInFullScreenBookMode);
             int changeToLog =
                     letterboxPositionForHorizontalReachability
                             == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER
@@ -388,11 +423,13 @@
             // Only react to clicks at the top and bottom of the letterboxed app window.
             return;
         }
+        boolean isInFullScreenTabletopMode = isDisplayFullScreenAndSeparatingHinge();
         int letterboxPositionForVerticalReachability = mLetterboxConfiguration
-                .getLetterboxPositionForVerticalReachability();
+                .getLetterboxPositionForVerticalReachability(isInFullScreenTabletopMode);
         if (mLetterbox.getInnerFrame().top > y) {
             // Moving to the next stop on the top side of the app window: bottom > center > top.
-            mLetterboxConfiguration.movePositionForVerticalReachabilityToNextTopStop();
+            mLetterboxConfiguration.movePositionForVerticalReachabilityToNextTopStop(
+                    isInFullScreenTabletopMode);
             int changeToLog =
                     letterboxPositionForVerticalReachability
                             == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER
@@ -401,7 +438,8 @@
             logLetterboxPositionChange(changeToLog);
         } else if (mLetterbox.getInnerFrame().bottom < y) {
             // Moving to the next stop on the bottom side of the app window: top > center > bottom.
-            mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop();
+            mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop(
+                    isInFullScreenTabletopMode);
             int changeToLog =
                     letterboxPositionForVerticalReachability
                             == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER
@@ -712,10 +750,10 @@
                 + getVerticalPositionMultiplier(mActivityRecord.getParent().getConfiguration()));
         pw.println(prefix + "  letterboxPositionForHorizontalReachability="
                 + LetterboxConfiguration.letterboxHorizontalReachabilityPositionToString(
-                    mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability()));
+                mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability(false)));
         pw.println(prefix + "  letterboxPositionForVerticalReachability="
                 + LetterboxConfiguration.letterboxVerticalReachabilityPositionToString(
-                    mLetterboxConfiguration.getLetterboxPositionForVerticalReachability()));
+                mLetterboxConfiguration.getLetterboxPositionForVerticalReachability(false)));
         pw.println(prefix + "  fixedOrientationLetterboxAspectRatio="
                 + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
         pw.println(prefix + "  defaultMinAspectRatioForUnresizableApps="
@@ -780,14 +818,20 @@
         int positionToLog = APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__UNKNOWN_POSITION;
         if (isHorizontalReachabilityEnabled()) {
             int letterboxPositionForHorizontalReachability = getLetterboxConfiguration()
-                    .getLetterboxPositionForHorizontalReachability();
+                    .getLetterboxPositionForHorizontalReachability(
+                            isDisplayFullScreenAndInPosture(
+                                    DeviceStateController.FoldState.HALF_FOLDED,
+                                    false /* isTabletop */));
             positionToLog = letterboxHorizontalReachabilityPositionToLetterboxPosition(
-                            letterboxPositionForHorizontalReachability);
+                    letterboxPositionForHorizontalReachability);
         } else if (isVerticalReachabilityEnabled()) {
             int letterboxPositionForVerticalReachability = getLetterboxConfiguration()
-                    .getLetterboxPositionForVerticalReachability();
+                    .getLetterboxPositionForVerticalReachability(
+                            isDisplayFullScreenAndInPosture(
+                                    DeviceStateController.FoldState.HALF_FOLDED,
+                                    true /* isTabletop */));
             positionToLog = letterboxVerticalReachabilityPositionToLetterboxPosition(
-                            letterboxPositionForVerticalReachability);
+                    letterboxPositionForVerticalReachability);
         }
         return positionToLog;
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 4e692e2d..85aa942 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -1219,9 +1219,17 @@
             pw.println("Corner radius: "
                     + mLetterboxConfiguration.getLetterboxActivityCornersRadius());
             pw.println("Horizontal position multiplier: "
-                    + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier());
+                    + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(
+                            false /* isInBookMode */));
             pw.println("Vertical position multiplier: "
-                    + mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier());
+                    + mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier(
+                            false /* isInTabletopMode */));
+            pw.println("Horizontal position multiplier (book mode): "
+                    + mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(
+                            true /* isInBookMode */));
+            pw.println("Vertical position multiplier (tabletop mode): "
+                    + mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier(
+                            true /* isInTabletopMode */));
             pw.println("Aspect ratio: "
                     + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
             pw.println("Default min aspect ratio for unresizable apps: "
@@ -1238,10 +1246,10 @@
                     mLetterboxConfiguration.getDefaultPositionForVerticalReachability()));
             pw.println("Current position for horizontal reachability:"
                     + LetterboxConfiguration.letterboxHorizontalReachabilityPositionToString(
-                        mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability()));
+                    mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability(false)));
             pw.println("Current position for vertical reachability:"
                     + LetterboxConfiguration.letterboxVerticalReachabilityPositionToString(
-                        mLetterboxConfiguration.getLetterboxPositionForVerticalReachability()));
+                    mLetterboxConfiguration.getLetterboxPositionForVerticalReachability(false)));
             pw.println("Is education enabled: "
                     + mLetterboxConfiguration.getIsEducationEnabled());
             pw.println("Is using split screen aspect ratio as aspect ratio for unresizable apps: "
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
index 1be9de7..51a7e74 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
@@ -67,6 +67,11 @@
                         R.integer.config_letterboxDefaultPositionForHorizontalReachability),
                 () -> mContext.getResources().getInteger(
                         R.integer.config_letterboxDefaultPositionForVerticalReachability),
+                () -> mContext.getResources().getInteger(
+                        R.integer.config_letterboxDefaultPositionForBookModeReachability),
+                () -> mContext.getResources().getInteger(
+                        R.integer.config_letterboxDefaultPositionForTabletopModeReachability
+                ),
                 mConfigFolder, mPersisterQueue, mQueueState);
         mQueueListener = queueEmpty -> mQueueState.onItemAdded();
         mPersisterQueue.addListener(mQueueListener);
@@ -84,14 +89,15 @@
     @Test
     public void test_whenStoreIsCreated_valuesAreDefaults() {
         final int positionForHorizontalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability(
+                        false);
         final int defaultPositionForHorizontalReachability =
                 mContext.getResources().getInteger(
                         R.integer.config_letterboxDefaultPositionForHorizontalReachability);
         Assert.assertEquals(defaultPositionForHorizontalReachability,
                 positionForHorizontalReachability);
         final int positionForVerticalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(false);
         final int defaultPositionForVerticalReachability =
                 mContext.getResources().getInteger(
                         R.integer.config_letterboxDefaultPositionForVerticalReachability);
@@ -101,15 +107,16 @@
 
     @Test
     public void test_whenUpdatedWithNewValues_valuesAreWritten() {
-        mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
+        mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(false,
                 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
-        mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
+        mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(false,
                 LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
         waitForCompletion(mPersisterQueue);
         final int newPositionForHorizontalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability(
+                        false);
         final int newPositionForVerticalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(false);
         Assert.assertEquals(LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
                 newPositionForHorizontalReachability);
         Assert.assertEquals(LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
@@ -120,24 +127,24 @@
     public void test_whenUpdatedWithNewValues_valuesAreReadAfterRestart() {
         final PersisterQueue firstPersisterQueue = new PersisterQueue();
         final LetterboxConfigurationPersister firstPersister = new LetterboxConfigurationPersister(
-                mContext, () -> -1, () -> -1, mContext.getFilesDir(), firstPersisterQueue,
-                mQueueState);
+                mContext, () -> -1, () -> -1, () -> -1, () -> -1, mContext.getFilesDir(),
+                firstPersisterQueue, mQueueState);
         firstPersister.start();
-        firstPersister.setLetterboxPositionForHorizontalReachability(
+        firstPersister.setLetterboxPositionForHorizontalReachability(false,
                 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
-        firstPersister.setLetterboxPositionForVerticalReachability(
+        firstPersister.setLetterboxPositionForVerticalReachability(false,
                 LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
         waitForCompletion(firstPersisterQueue);
         stopPersisterSafe(firstPersisterQueue);
         final PersisterQueue secondPersisterQueue = new PersisterQueue();
         final LetterboxConfigurationPersister secondPersister = new LetterboxConfigurationPersister(
-                mContext, () -> -1, () -> -1, mContext.getFilesDir(), secondPersisterQueue,
-                mQueueState);
+                mContext, () -> -1, () -> -1, () -> -1, () -> -1, mContext.getFilesDir(),
+                secondPersisterQueue, mQueueState);
         secondPersister.start();
         final int newPositionForHorizontalReachability =
-                secondPersister.getLetterboxPositionForHorizontalReachability();
+                secondPersister.getLetterboxPositionForHorizontalReachability(false);
         final int newPositionForVerticalReachability =
-                secondPersister.getLetterboxPositionForVerticalReachability();
+                secondPersister.getLetterboxPositionForVerticalReachability(false);
         Assert.assertEquals(LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
                 newPositionForHorizontalReachability);
         Assert.assertEquals(LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
@@ -149,15 +156,16 @@
 
     @Test
     public void test_whenUpdatedWithNewValuesAndDeleted_valuesAreDefaults() {
-        mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
+        mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(false,
                 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
-        mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
+        mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(false,
                 LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
         waitForCompletion(mPersisterQueue);
         final int newPositionForHorizontalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability(
+                        false);
         final int newPositionForVerticalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(false);
         Assert.assertEquals(LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
                 newPositionForHorizontalReachability);
         Assert.assertEquals(LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
@@ -165,14 +173,15 @@
         deleteConfiguration(mLetterboxConfigurationPersister, mPersisterQueue);
         waitForCompletion(mPersisterQueue);
         final int positionForHorizontalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability(
+                        false);
         final int defaultPositionForHorizontalReachability =
                 mContext.getResources().getInteger(
                         R.integer.config_letterboxDefaultPositionForHorizontalReachability);
         Assert.assertEquals(defaultPositionForHorizontalReachability,
                 positionForHorizontalReachability);
         final int positionForVerticalReachability =
-                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
+                mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability(false);
         final int defaultPositionForVerticalReachability =
                 mContext.getResources().getInteger(
                         R.integer.config_letterboxDefaultPositionForVerticalReachability);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
index c927f9e..e196704 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
@@ -26,6 +26,7 @@
 import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
 
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -39,7 +40,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.function.Consumer;
+import java.util.Arrays;
+import java.util.function.BiConsumer;
 
 @SmallTest
 @Presubmit
@@ -58,20 +60,28 @@
 
     @Test
     public void test_whenReadingValues_storeIsInvoked() {
-        mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability();
-        verify(mLetterboxConfigurationPersister).getLetterboxPositionForHorizontalReachability();
-        mLetterboxConfiguration.getLetterboxPositionForVerticalReachability();
-        verify(mLetterboxConfigurationPersister).getLetterboxPositionForVerticalReachability();
+        for (boolean halfFoldPose : Arrays.asList(false, true)) {
+            mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability(halfFoldPose);
+            verify(mLetterboxConfigurationPersister).getLetterboxPositionForHorizontalReachability(
+                    halfFoldPose);
+            mLetterboxConfiguration.getLetterboxPositionForVerticalReachability(halfFoldPose);
+            verify(mLetterboxConfigurationPersister).getLetterboxPositionForVerticalReachability(
+                    halfFoldPose);
+        }
     }
 
     @Test
     public void test_whenSettingValues_updateConfigurationIsInvoked() {
-        mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop();
-        verify(mLetterboxConfigurationPersister).setLetterboxPositionForHorizontalReachability(
-                anyInt());
-        mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop();
-        verify(mLetterboxConfigurationPersister).setLetterboxPositionForVerticalReachability(
-                anyInt());
+        for (boolean halfFoldPose : Arrays.asList(false, true)) {
+            mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop(
+                    halfFoldPose);
+            verify(mLetterboxConfigurationPersister).setLetterboxPositionForHorizontalReachability(
+                    eq(halfFoldPose), anyInt());
+            mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop(
+                    halfFoldPose);
+            verify(mLetterboxConfigurationPersister).setLetterboxPositionForVerticalReachability(
+                    eq(halfFoldPose), anyInt());
+        }
     }
 
     @Test
@@ -81,33 +91,65 @@
                 /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
                 /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
                 /* expectedTime */ 1,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForHorizontalReachabilityToNextLeftStop);
         assertForHorizontalMove(
                 /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
                 /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
                 /* expectedTime */ 1,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForHorizontalReachabilityToNextRightStop);
         // Starting from left
         assertForHorizontalMove(
                 /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
                 /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
                 /* expectedTime */ 2,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForHorizontalReachabilityToNextLeftStop);
         assertForHorizontalMove(
                 /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
                 /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
                 /* expectedTime */ 1,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForHorizontalReachabilityToNextRightStop);
         // Starting from right
         assertForHorizontalMove(
                 /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
                 /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
                 /* expectedTime */ 2,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForHorizontalReachabilityToNextRightStop);
         assertForHorizontalMove(
                 /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
                 /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
                 /* expectedTime */ 2,
+                /* halfFoldPose */ false,
+                LetterboxConfiguration::movePositionForHorizontalReachabilityToNextLeftStop);
+        // Starting from left - book mode
+        assertForHorizontalMove(
+                /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
+                /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
+                /* expectedTime */ 1,
+                /* halfFoldPose */ true,
+                LetterboxConfiguration::movePositionForHorizontalReachabilityToNextLeftStop);
+        assertForHorizontalMove(
+                /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
+                /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
+                /* expectedTime */ 1,
+                /* halfFoldPose */ true,
+                LetterboxConfiguration::movePositionForHorizontalReachabilityToNextRightStop);
+        // Starting from right - book mode
+        assertForHorizontalMove(
+                /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
+                /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
+                /* expectedTime */ 2,
+                /* halfFoldPose */ true,
+                LetterboxConfiguration::movePositionForHorizontalReachabilityToNextRightStop);
+        assertForHorizontalMove(
+                /* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
+                /* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
+                /* expectedTime */ 2,
+                /* halfFoldPose */ true,
                 LetterboxConfiguration::movePositionForHorizontalReachabilityToNextLeftStop);
     }
 
@@ -118,55 +160,87 @@
                 /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
                 /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
                 /* expectedTime */ 1,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop);
         assertForVerticalMove(
                 /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
                 /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
                 /* expectedTime */ 1,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForVerticalReachabilityToNextTopStop);
         // Starting from top
         assertForVerticalMove(
                 /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
                 /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
                 /* expectedTime */ 1,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop);
         assertForVerticalMove(
                 /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
                 /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
                 /* expectedTime */ 2,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForVerticalReachabilityToNextTopStop);
         // Starting from bottom
         assertForVerticalMove(
                 /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
                 /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
                 /* expectedTime */ 2,
+                /* halfFoldPose */ false,
                 LetterboxConfiguration::movePositionForVerticalReachabilityToNextTopStop);
         assertForVerticalMove(
                 /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
                 /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
                 /* expectedTime */ 2,
+                /* halfFoldPose */ false,
+                LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop);
+        // Starting from top - tabletop mode
+        assertForVerticalMove(
+                /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
+                /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
+                /* expectedTime */ 1,
+                /* halfFoldPose */ true,
+                LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop);
+        assertForVerticalMove(
+                /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
+                /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
+                /* expectedTime */ 1,
+                /* halfFoldPose */ true,
+                LetterboxConfiguration::movePositionForVerticalReachabilityToNextTopStop);
+        // Starting from bottom - tabletop mode
+        assertForVerticalMove(
+                /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
+                /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
+                /* expectedTime */ 2,
+                /* halfFoldPose */ true,
+                LetterboxConfiguration::movePositionForVerticalReachabilityToNextTopStop);
+        assertForVerticalMove(
+                /* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
+                /* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
+                /* expectedTime */ 2,
+                /* halfFoldPose */ true,
                 LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop);
     }
 
     private void assertForHorizontalMove(int from, int expected, int expectedTime,
-            Consumer<LetterboxConfiguration> move) {
+            boolean halfFoldPose, BiConsumer<LetterboxConfiguration, Boolean> move) {
         // We are in the current position
-        when(mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability())
+        when(mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability(halfFoldPose))
                 .thenReturn(from);
-        move.accept(mLetterboxConfiguration);
+        move.accept(mLetterboxConfiguration, halfFoldPose);
         verify(mLetterboxConfigurationPersister,
-                times(expectedTime)).setLetterboxPositionForHorizontalReachability(
+                times(expectedTime)).setLetterboxPositionForHorizontalReachability(halfFoldPose,
                 expected);
     }
 
     private void assertForVerticalMove(int from, int expected, int expectedTime,
-            Consumer<LetterboxConfiguration> move) {
+            boolean halfFoldPose, BiConsumer<LetterboxConfiguration, Boolean> move) {
         // We are in the current position
-        when(mLetterboxConfiguration.getLetterboxPositionForVerticalReachability())
+        when(mLetterboxConfiguration.getLetterboxPositionForVerticalReachability(halfFoldPose))
                 .thenReturn(from);
-        move.accept(mLetterboxConfiguration);
+        move.accept(mLetterboxConfiguration, halfFoldPose);
         verify(mLetterboxConfigurationPersister,
-                times(expectedTime)).setLetterboxPositionForVerticalReachability(
+                times(expectedTime)).setLetterboxPositionForVerticalReachability(halfFoldPose,
                 expected);
     }
 }
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 94c33f2..7488e1c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -95,6 +96,7 @@
 import com.android.internal.policy.SystemBarUtils;
 import com.android.internal.statusbar.LetterboxDetails;
 import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.DeviceStateController.FoldState;
 
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -2821,6 +2823,70 @@
     }
 
     @Test
+    public void testUpdateResolvedBoundsVerticalPosition_tabletop() {
+
+        // Set up a display in portrait with a fixed-orientation LANDSCAPE app
+        setUpDisplaySizeWithApp(1400, 2800);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(
+                1.0f /*letterboxVerticalPositionMultiplier*/);
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+        Rect letterboxNoFold = new Rect(0, 2100, 1400, 2800);
+        assertEquals(letterboxNoFold, mActivity.getBounds());
+
+        // Make the activity full-screen
+        mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+        setFoldablePosture(true /* isHalfFolded */, true /* isTabletop */);
+
+        Rect letterboxHalfFold = new Rect(0, 0, 1400, 700);
+        assertEquals(letterboxHalfFold, mActivity.getBounds());
+
+        setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */);
+
+        assertEquals(letterboxNoFold, mActivity.getBounds());
+
+    }
+
+    @Test
+    public void testUpdateResolvedBoundsHorizontalPosition_book() {
+
+        // Set up a display in landscape with a fixed-orientation PORTRAIT app
+        setUpDisplaySizeWithApp(2800, 1400);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
+                1.0f /*letterboxVerticalPositionMultiplier*/);
+        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+        Rect letterboxNoFold = new Rect(2100, 0, 2800, 1400);
+        assertEquals(letterboxNoFold, mActivity.getBounds());
+
+        // Make the activity full-screen
+        mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+        setFoldablePosture(true /* isHalfFolded */, false /* isTabletop */);
+
+        Rect letterboxHalfFold = new Rect(0, 0, 700, 1400);
+        assertEquals(letterboxHalfFold, mActivity.getBounds());
+
+        setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */);
+
+        assertEquals(letterboxNoFold, mActivity.getBounds());
+
+    }
+
+    private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) {
+        final DisplayRotation r = mActivity.mDisplayContent.getDisplayRotation();
+        doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge();
+        doReturn(false).when(r).isDeviceInPosture(any(FoldState.class), anyBoolean());
+        if (isHalfFolded) {
+            doReturn(true).when(r).isDeviceInPosture(FoldState.HALF_FOLDED, isTabletop);
+        }
+        mActivity.recomputeConfiguration();
+    }
+
+    @Test
     public void testUpdateResolvedBoundsPosition_alignToTop() {
         final int notchHeight = 100;
         final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800)