From 7274a6e2591ec72ab61019e1e591547297e756d5 Mon Sep 17 00:00:00 2001 From: Loukious <24696530+Loukious@users.noreply.github.com> Date: Fri, 31 Jul 2026 22:03:16 +0100 Subject: [PATCH] wm: add configurable gesture navigation space Allow users to reduce or remove the space reserved by the gesture navigation bar. Apply the selected mode while DisplayPolicy processes navigationBars inset providers so the feature works with both SystemUI navigation bars and launcher-owned taskbars. Keep mandatory system gesture insets unchanged so Home and Recents continue to work. Compact uses 50 percent of the original navigation bar inset, while Minimal reports no navigation bar inset. --- core/java/android/provider/Settings.java | 8 ++ .../com/android/server/wm/DisplayPolicy.java | 77 ++++++++++++++++++- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 639f509915b30..81704862710cd 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7412,6 +7412,14 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean */ public static final String GESTURE_NAVBAR_HEIGHT_MODE = "gesture_navbar_height_mode"; + /** + * Controls the amount of space reserved for the gesture navigation bar. + * Supported modes: 0 for default, 1 for compact and 2 for minimal. + * @hide + */ + public static final String GESTURE_NAVBAR_SPACE_MODE = + "gesture_navbar_space_mode"; + /** * Whether allowing pocket service to register sensors and dispatch informations. * 0 = disabled diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 2ff2e71dcefc6..33cb3a53f9eec 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -65,6 +65,7 @@ import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED; import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.window.DesktopExperienceFlags.ENABLE_RESTRICT_FREEFORM_HIDDEN_SYSTEM_BARS_TO_FILLING_TASKS; import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; @@ -191,6 +192,13 @@ public class DisplayPolicy { private static final int INSETS_OVERRIDE_INDEX_INVALID = -1; + private static final int GESTURE_NAVBAR_SPACE_DEFAULT = 0; + private static final int GESTURE_NAVBAR_SPACE_COMPACT = 1; + private static final int GESTURE_NAVBAR_SPACE_MINIMAL = 2; + + // Compact uses 50% of the provider's original inset. + private static final float GESTURE_NAVBAR_COMPACT_SCALE = 0.50f; + // TODO(b/266197298): Remove this by a more general protocol from the insets providers. private static final boolean USE_CACHED_INSETS_FOR_DISPLAY_SWITCH = SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", true); @@ -260,6 +268,8 @@ UiModeManagerInternal getUiModeManagerInternal() { private volatile boolean mHasStatusBar; private volatile boolean mHasNavigationBar; private volatile boolean mTaskBarEnabled; + private volatile int mGestureNavbarSpaceMode = + GESTURE_NAVBAR_SPACE_DEFAULT; // Can the navigation bar ever move to the side? private volatile boolean mNavigationBarCanMove; private volatile boolean mNavigationBarAlwaysShowOnSideGesture; @@ -457,13 +467,23 @@ public SettingsObserver(Handler handler) { resolver.registerContentObserver(LineageSettings.System.getUriFor( LineageSettings.System.ENABLE_TASKBAR), false, this, UserHandle.USER_ALL); + resolver.registerContentObserver( + Settings.System.getUriFor( + Settings.System.GESTURE_NAVBAR_SPACE_MODE), + false, + this, + UserHandle.USER_ALL); updateSettings(); } @Override public void onChange(boolean selfChange) { - updateSettings(); + synchronized (mLock) { + updateSettings(); + mDisplayContent.setLayoutNeeded(); + mService.requestTraversal(); + } } } @@ -799,6 +819,12 @@ public void updateSettings() { mTaskBarEnabled = LineageSettings.System.getIntForUser(resolver, LineageSettings.System.ENABLE_TASKBAR, isTablet() ? 1 : 0, UserHandle.USER_CURRENT) != 0; + + mGestureNavbarSpaceMode = Settings.System.getIntForUser( + resolver, + Settings.System.GESTURE_NAVBAR_SPACE_MODE, + GESTURE_NAVBAR_SPACE_DEFAULT, + UserHandle.USER_CURRENT); } private boolean isTablet() { @@ -1328,8 +1354,51 @@ void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) { } } + private static int scaleGestureNavbarInset(int value) { + if (value <= 0) { + return value; + } + return Math.max( + 1, + Math.round(value * GESTURE_NAVBAR_COMPACT_SCALE)); + } + + @Nullable + private Insets adjustGestureNavbarInsets( + InsetsFrameProvider provider, + @Nullable Insets originalInsets) { + if (provider.getType() != Type.navigationBars()) { + return originalInsets; + } + + final int interactionMode = getCurrentUserResources().getInteger( + R.integer.config_navBarInteractionMode); + if (interactionMode != NAV_BAR_MODE_GESTURAL) { + return originalInsets; + } + + switch (mGestureNavbarSpaceMode) { + case GESTURE_NAVBAR_SPACE_COMPACT: + if (originalInsets == null) { + return null; + } + return Insets.of( + scaleGestureNavbarInset(originalInsets.left), + scaleGestureNavbarInset(originalInsets.top), + scaleGestureNavbarInset(originalInsets.right), + scaleGestureNavbarInset(originalInsets.bottom)); + + case GESTURE_NAVBAR_SPACE_MINIMAL: + return Insets.NONE; + + case GESTURE_NAVBAR_SPACE_DEFAULT: + default: + return originalInsets; + } + } + @NonNull - private static TriFunction getFrameProvider( + private TriFunction getFrameProvider( WindowState win, int index, int overrideIndex) { return (displayFrames, windowState, inOutFrame) -> { final LayoutParams lp = win.mAttrs.forRotation(displayFrames.mRotation); @@ -1352,10 +1421,12 @@ private static TriFunction getFramePr inOutFrame.set(ifp.getArbitraryRectangle()); break; } - final Insets insetsSize = overrideIndex == INSETS_OVERRIDE_INDEX_INVALID + Insets insetsSize = overrideIndex == INSETS_OVERRIDE_INDEX_INVALID ? ifp.getInsetsSize() : ifp.getInsetsSizeOverrides()[overrideIndex].getInsetsSize(); + insetsSize = adjustGestureNavbarInsets(ifp, insetsSize); + if (ifp.getMinimalInsetsSizeInDisplayCutoutSafe() != null) { sTmpRect2.set(inOutFrame); }