diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7119aefaf8f8a4cdd5faaa95828c77ed7ee34dd7..75784308fe81b2482007155d36e00b5c636ec341 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5626,6 +5626,12 @@ public final class Settings { */ public static final String CAMERA_LAUNCH = "camera_launch"; + /** + * Force show navigation bar setting. + * @hide + */ + public static final String FORCE_SHOW_NAVBAR = "force_show_navbar"; + /** * IMPORTANT: If you add a new public settings you also have to add it to * PUBLIC_SETTINGS below. If the new setting is hidden you have to add diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index b64d25a5b72cb3b98df5d6caef6c95d5baac112a..ac214aa526d2bb28f0df8ec3ec1cfff68902f696 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -915,4 +915,9 @@ interface IWindowManager * reverts to using the default task transition with no spec changes. */ void clearTaskTransitionSpec(); + + /** + * Notifies DisplayPolicy that overlays changed. + */ + void onOverlayChanged(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java index 6f4e22fa8a0436a72adac360077afc119b2ce416..dec20f3b0386b830f26ba07b39bc1c4c13a3ff87 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java @@ -37,6 +37,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Rect; +import android.os.UserHandle; import android.os.SystemProperties; import android.provider.Settings; import android.util.DisplayMetrics; @@ -484,6 +485,11 @@ public class DisplayLayout { static boolean hasNavigationBar(DisplayInfo info, Context context, int displayId) { if (displayId == Display.DEFAULT_DISPLAY) { + if (Settings.System.getIntForUser(context.getContentResolver(), + Settings.System.FORCE_SHOW_NAVBAR, 0, + UserHandle.USER_CURRENT) == 1) { + return true; + } // Allow a system property to override this. Used by the emulator. final String navBarOverride = SystemProperties.get("qemu.hw.mainkeys"); if ("1".equals(navBarOverride)) { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index 85d5de0ea4f69ddde33f2bd73c8a3183c979eaa7..ce99543a3ae766a265a381c89d029a1e3e2bd127 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -23,11 +23,15 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT; import android.app.WindowConfiguration; +import android.content.Context; import android.graphics.Rect; import android.os.Handler; +import android.os.UserHandle; import android.os.RemoteException; +import android.provider.Settings; import android.util.Log; import android.view.InsetsController; +import android.view.Display; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.WindowManager; @@ -191,7 +195,13 @@ public class WindowManagerWrapper { * * @return whether there is a soft nav bar on specific display. */ - public boolean hasSoftNavigationBar(int displayId) { + public boolean hasSoftNavigationBar(Context context, int displayId) { + if (displayId == Display.DEFAULT_DISPLAY && + Settings.System.getIntForUser(context.getContentResolver(), + Settings.System.FORCE_SHOW_NAVBAR, 0, + UserHandle.USER_CURRENT) == 1) { + return true; + } try { return WindowManagerGlobal.getWindowManagerService().hasNavigationBar(displayId); } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index a984974c6bbaecf593a771b3667cd984bb63c07f..58538564a6e711de63dfa334add3a338bfa74536 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -53,6 +53,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.model.SysUiState; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.phone.AutoHideController; @@ -299,20 +300,15 @@ public class NavigationBarController implements return; } + final WindowManagerWrapper wm = WindowManagerWrapper.getInstance(); final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); - try { - if (!wms.hasNavigationBar(displayId)) { - return; - } - } catch (RemoteException e) { - // Cannot get wms, just return with warning message. - Log.w(TAG, "Cannot get WindowManager."); - return; - } final Context context = isOnDefaultDisplay ? mContext : mContext.createDisplayContext(display); + if (!wm.hasSoftNavigationBar(context, displayId)) { + return; + } NavigationBar navBar = mNavigationBarFactory.create(context); mNavigationBars.put(displayId, navBar); @@ -333,6 +329,12 @@ public class NavigationBarController implements v.removeOnAttachStateChangeListener(this); } }); + + try { + wms.onOverlayChanged(); + } catch (RemoteException e) { + // Do nothing. + } } void removeNavigationBar(int displayId) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index 7f130cb203c0edb4896883b32df623ce3d61f5e7..c481ae59faa57b9e88bf4d2924c937282d80e613 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -250,7 +250,8 @@ public class ScreenPinningRequest implements View.OnClickListener, View buttons = mLayout.findViewById(R.id.screen_pinning_buttons); WindowManagerWrapper wm = WindowManagerWrapper.getInstance(); if (!QuickStepContract.isGesturalMode(mNavBarMode) - && wm.hasSoftNavigationBar(mContext.getDisplayId()) && !isTablet(mContext)) { + && wm.hasSoftNavigationBar(mContext, mContext.getDisplayId()) + && !isTablet(mContext)) { buttons.setLayoutDirection(View.LAYOUT_DIRECTION_LOCALE); swapChildrenIfRtlAndVertical(buttons); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index b2c2ebb179b86025f71c7f1ead18269e10b293bd..28c379480f5da022d69dc925cc0ccb20c3110994 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -238,6 +238,7 @@ import com.android.systemui.util.DumpUtilsKt; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.MessageRouter; +import com.android.systemui.tuner.TunerService; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubbles; @@ -260,7 +261,8 @@ import dagger.Lazy; /** */ public class StatusBar extends SystemUI implements ActivityStarter, - LifecycleOwner { + LifecycleOwner, + TunerService.Tunable { public static final boolean MULTIUSER_DEBUG = false; protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027; @@ -269,6 +271,9 @@ public class StatusBar extends SystemUI implements public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot"; + private static final String FORCE_SHOW_NAVBAR = + "customsystem:" + Settings.System.FORCE_SHOW_NAVBAR; + private static final String BANNER_ACTION_CANCEL = "com.android.systemui.statusbar.banner_action_cancel"; private static final String BANNER_ACTION_SETUP = @@ -934,6 +939,19 @@ public class StatusBar extends SystemUI implements mStatusBarStateController.addCallback(mStateListener, SysuiStatusBarStateController.RANK_STATUS_BAR); + mNeedsNavigationBar = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_showNavigationBar); + // Allow a system property to override this. Used by the emulator. + // See also hasNavigationBar(). + String navBarOverride = SystemProperties.get("qemu.hw.mainkeys"); + if ("1".equals(navBarOverride)) { + mNeedsNavigationBar = false; + } else if ("0".equals(navBarOverride)) { + mNeedsNavigationBar = true; + } + + mTunerService.addTunable(this, FORCE_SHOW_NAVBAR); + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mDreamManager = IDreamManager.Stub.asInterface( ServiceManager.checkService(DreamService.DREAM_SERVICE)); @@ -3840,6 +3858,7 @@ public class StatusBar extends SystemUI implements private final NavigationBarController mNavigationBarController; private final AccessibilityFloatingMenuController mAccessibilityFloatingMenuController; + private boolean mNeedsNavigationBar; // UI-specific methods @@ -4157,6 +4176,25 @@ public class StatusBar extends SystemUI implements public NotificationPanelViewController getPanelController() { return mNotificationPanelViewController; } + + @Override + public void onTuningChanged(String key, String newValue) { + if (FORCE_SHOW_NAVBAR.equals(key) && mDisplayId == Display.DEFAULT_DISPLAY && + mWindowManagerService != null) { + boolean forcedVisibility = mNeedsNavigationBar || + TunerService.parseIntegerSwitch(newValue, false); + boolean hasNavbar = getNavigationBarView() != null; + if (forcedVisibility) { + if (!hasNavbar) { + mNavigationBarController.onDisplayReady(mDisplayId); + } + } else { + if (hasNavbar) { + mNavigationBarController.onDisplayRemoved(mDisplayId); + } + } + } + } // End Extra BaseStatusBarMethods. public NotificationGutsManager getGutsManager() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 20575ae504ad260034bc316e6d148d8a3bfdc9c5..fd9005ee761512c04a1120383a66609b4785e949 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -147,6 +147,7 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.window.StatusBarWindowController; import com.android.systemui.tuner.TunerService; import com.android.systemui.util.WallpaperController; +import com.android.systemui.tuner.TunerService; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.MessageRouterImpl; import com.android.systemui.util.time.FakeSystemClock; @@ -278,6 +279,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private OperatorNameViewController mOperatorNameViewController; @Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; @Mock private ActivityLaunchAnimator mActivityLaunchAnimator; + @Mock private TunerService mTunerService; private ShadeController mShadeController; private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index b4b0a9bae6d1cf4becc1d3f53170522ffa3cdf2b..7650abee808b7ede2a2e5673db4a23118040ad98 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -563,6 +563,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mPendingMetaAction; boolean mPendingCapsLockToggle; + private int mForceNavbar = -1; + // Tracks user-customisable behavior for certain key events private Action mBackLongPressAction; private Action mHomeLongPressAction; @@ -697,10 +699,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { private int mTorchTimeout; private PendingIntent mTorchOffPendingIntent; - private LineageHardwareManager mLineageHardware; - private boolean mLongSwipeDown; + private LineageHardwareManager mLineageHardware; + private class PolicyHandler extends Handler { @Override public void handleMessage(Message msg) { @@ -859,6 +861,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.KEY_HOME_DOUBLE_TAP_ACTION), false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.FORCE_SHOW_NAVBAR), false, this, + UserHandle.USER_ALL); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.KEY_MENU_ACTION), false, this, UserHandle.USER_ALL); @@ -2354,6 +2359,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void updateKeyAssignments() { int activeHardwareKeys = mDeviceHardwareKeys; + if (mForceNavbar == 1) { + activeHardwareKeys = 0; + } + final boolean hasMenu = (activeHardwareKeys & KEY_MASK_MENU) != 0; final boolean hasAssist = (activeHardwareKeys & KEY_MASK_ASSIST) != 0; final boolean hasAppSwitch = (activeHardwareKeys & KEY_MASK_APP_SWITCH) != 0; @@ -2526,6 +2535,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateWakeGestureListenerLp(); } + int forceNavbar = Settings.System.getIntForUser(resolver, + Settings.System.FORCE_SHOW_NAVBAR, 0, + UserHandle.USER_CURRENT); + if (forceNavbar != mForceNavbar) { + mForceNavbar = forceNavbar; + if (mLineageHardware.isSupported(LineageHardwareManager.FEATURE_KEY_DISABLE)) { + mLineageHardware.set(LineageHardwareManager.FEATURE_KEY_DISABLE, + mForceNavbar == 1); + } + } + updateKeyAssignments(); // use screen off timeout setting as the timeout for the lockscreen diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index e03e2cf2480e97959c538a5c1aebc13d47740d57..14fd18f053f6e00e8202605b312bf80f3d6ec6ab 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -949,6 +949,8 @@ public final class PowerManagerService extends SystemService private static native boolean nativeSetPowerMode(int mode, boolean enabled); private static native boolean nativeForceSuspend(); + private boolean mForceNavbar; + // Whether proximity check on wake is enabled by default private boolean mProximityWakeEnabledByDefaultConfig; @@ -1261,6 +1263,9 @@ public final class PowerManagerService extends SystemService resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.WAKE_WHEN_PLUGGED_OR_UNPLUGGED), false, mSettingsObserver, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.FORCE_SHOW_NAVBAR), + false, mSettingsObserver, UserHandle.USER_ALL); IVrManager vrManager = IVrManager.Stub.asInterface(getBinderService(Context.VR_SERVICE)); if (vrManager != null) { try { @@ -1403,6 +1408,9 @@ public final class PowerManagerService extends SystemService Settings.Secure.PROXIMITY_ON_WAKE, mProximityWakeEnabledByDefaultConfig ? 1 : 0, UserHandle.USER_CURRENT) == 1; + mForceNavbar = Settings.System.getIntForUser(resolver, + Settings.System.FORCE_SHOW_NAVBAR, + 0, UserHandle.USER_CURRENT) == 1; mDirty |= DIRTY_SETTINGS; } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 1ff2ebeb8c14ffbc140c8da1d19d60abeb540f99..eb88eb4a1f6a52f12f5927f0744f800dcae71603 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -114,10 +114,12 @@ import android.app.ActivityManager; import android.app.ActivityThread; import android.app.LoadedApk; import android.app.ResourcesManager; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.database.ContentObserver; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Point; @@ -132,6 +134,7 @@ import android.os.Message; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.provider.Settings; import android.util.ArraySet; import android.util.PrintWriterPrinter; import android.util.Slog; @@ -256,6 +259,7 @@ public class DisplayPolicy { private volatile boolean mHasStatusBar; private volatile boolean mHasNavigationBar; + private volatile int mForceNavbar = -1; // Can the navigation bar ever move to the side? private volatile boolean mNavigationBarCanMove; private volatile boolean mNavigationBarLetsThroughTaps; @@ -395,6 +399,8 @@ public class DisplayPolicy { private RefreshRatePolicy mRefreshRatePolicy; + private SettingsObserver mSettingsObserver; + /** * If true, attach the navigation bar to the current transition app. * The value is read from config_attachNavBarToAppDuringTransition and could be overlaid by RRO @@ -446,6 +452,24 @@ public class DisplayPolicy { } } + private class SettingsObserver extends ContentObserver { + public SettingsObserver(Handler handler) { + super(handler); + + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.FORCE_SHOW_NAVBAR), false, this, + UserHandle.USER_ALL); + + updateSettings(); + } + + @Override + public void onChange(boolean selfChange) { + updateSettings(); + } + } + DisplayPolicy(WindowManagerService service, DisplayContent displayContent) { mService = service; mContext = displayContent.isDefaultDisplay ? service.mContext @@ -676,6 +700,9 @@ public class DisplayPolicy { } else if ("0".equals(navBarOverride)) { mHasNavigationBar = true; } + + // Register content observer only for main display + mSettingsObserver = new SettingsObserver(mHandler); } else { mHasStatusBar = false; mHasNavigationBar = mDisplayContent.supportsSystemDecorations(); @@ -738,6 +765,14 @@ public class DisplayPolicy { } } + public void updateSettings() { + ContentResolver resolver = mContext.getContentResolver(); + + mForceNavbar = Settings.System.getIntForUser(resolver, + Settings.System.FORCE_SHOW_NAVBAR, 0, + UserHandle.USER_CURRENT); + } + private int getDisplayId() { return mDisplayContent.getDisplayId(); } @@ -786,7 +821,7 @@ public class DisplayPolicy { } public boolean hasNavigationBar() { - return mHasNavigationBar; + return mHasNavigationBar || mForceNavbar == 1; } public boolean hasStatusBar() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4258e073429eefb84fb6defd25ec8783338419e3..2d9ef16e158029a61ad64148a8b619d77a5869ce 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6839,6 +6839,7 @@ public class WindowManagerService extends IWindowManager.Stub return mRoot.getDisplayContent(DEFAULT_DISPLAY); } + @Override public void onOverlayChanged() { synchronized (mGlobalLock) { mRoot.forAllDisplays(displayContent -> {