Make some IStatusBar APIs support multi-display(1/N)

In this CL, we add parameter displayId in some IStatusBar APIs and also
group flags into an inner class and make it exist per display.

TODO: 1. We left SystemUi implementation in later CL.
      2. Investigate which part of disable should support multi-display
         after main function completes.
      3. Refactor registerStatusBar as an IStatusBar API.
Note: remove mLightsOutListener in NavigationBarTransitions since no one uses it.

Test: atest SystemUITests
Bug: 117478341

Change-Id: Ie50a72f5d18e1f055ff2be4f1d7ac06da0117051
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 600b1b3..53b56f2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -29,7 +29,7 @@
 {
     void setIcon(String slot, in StatusBarIcon icon);
     void removeIcon(String slot);
-    void disable(int state1, int state2);
+    void disable(int displayId, int state1, int state2);
     void animateExpandNotificationsPanel();
     void animateExpandSettingsPanel(String subPanel);
     void animateCollapsePanels();
@@ -38,8 +38,9 @@
     void showWirelessChargingAnimation(int batteryLevel);
 
     /**
-     * Notifies the status bar of a System UI visibility flag change.
+     * Notifies System UI side of a visibility flag change on the specified display.
      *
+     * @param displayId the id of the display to notify
      * @param vis the visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will be reported
      *            separately in fullscreenStackVis and dockedStackVis
      * @param fullscreenStackVis the flags which only apply in the region of the fullscreen stack,
@@ -50,13 +51,13 @@
      * @param fullscreenBounds the current bounds of the fullscreen stack, in screen coordinates
      * @param dockedBounds the current bounds of the docked stack, in screen coordinates
      */
-    void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
-            in Rect fullscreenBounds, in Rect dockedBounds);
+    void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis,
+            int mask, in Rect fullscreenBounds, in Rect dockedBounds);
 
-    void topAppWindowChanged(boolean menuVisible);
-    void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+    void topAppWindowChanged(int displayId, boolean menuVisible);
+    void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher);
-    void setWindowState(int window, int state);
+    void setWindowState(int display, int window, int state);
 
     void showRecentApps(boolean triggeredFromAltTab);
     void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
@@ -70,30 +71,38 @@
     void toggleKeyboardShortcutsMenu(int deviceId);
 
     /**
-     * Notifies the status bar that an app transition is pending to delay applying some flags with
-     * visual impact until {@link #appTransitionReady} is called.
-     */
-    void appTransitionPending();
-
-    /**
-     * Notifies the status bar that a pending app transition has been cancelled.
-     */
-    void appTransitionCancelled();
-
-    /**
-     * Notifies the status bar that an app transition is now being executed.
+     * Notifies System UI on the specified display that an app transition is pending to delay
+     * applying some flags with visual impact until {@link #appTransitionReady} is called.
      *
+     * @param displayId the id of the display to notify
+     */
+    void appTransitionPending(int displayId);
+
+    /**
+     * Notifies System UI on the specified display that a pending app transition has been cancelled.
+     *
+     * @param displayId the id of the display to notify
+     */
+    void appTransitionCancelled(int displayId);
+
+    /**
+     * Notifies System UI on the specified display that an app transition is now being executed.
+     *
+     * @param displayId the id of the display to notify
      * @param statusBarAnimationsStartTime the desired start time for all visual animations in the
      *        status bar caused by this app transition in uptime millis
      * @param statusBarAnimationsDuration the duration for all visual animations in the status
      *        bar caused by this app transition in millis
      */
-    void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
+    void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
+            long statusBarAnimationsDuration);
 
     /**
-     * Notifies the status bar that an app transition is done.
+     * Notifies System UI on the specified display that an app transition is done.
+     *
+     * @param displayId the id of the display to notify
      */
-    void appTransitionFinished();
+    void appTransitionFinished(int displayId);
 
     void showAssistDisclosure();
     void startAssist(in Bundle args);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index bf82dc61..5118e5f 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -41,6 +41,7 @@
     void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription);
     void setIconVisibility(String slot, boolean visible);
     void removeIcon(String slot);
+    // TODO(b/117478341): support back button change when IME is showing on a external display.
     void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher);
     void expandSettingsPanel(String subPanel);
@@ -69,7 +70,7 @@
     void onNotificationSmartRepliesAdded(in String key, in int replyCount);
     void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply, boolean generatedByAssistant);
     void onNotificationSettingsViewed(String key);
-    void setSystemUiVisibility(int vis, int mask, String cause);
+    void setSystemUiVisibility(int displayId, int vis, int mask, String cause);
 
     void onGlobalActionsShown();
     void onGlobalActionsHidden();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 8b93995..b550274 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -223,7 +223,9 @@
         }
     }
 
-    public void disable(int state1, int state2) {
+    // TODO(b/117478341): Add multi-display support.
+    @Override
+    public void disable(int displayId, int state1, int state2) {
         disable(state1, state2, true);
     }
 
@@ -266,8 +268,10 @@
         }
     }
 
-    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
-            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+    // TODO(b/117478341): Add multi-display support.
+    @Override
+    public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+            int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
         synchronized (mLock) {
             // Don't coalesce these, since it might have one time flags set such as
             // STATUS_BAR_UNHIDE which might get lost.
@@ -282,7 +286,9 @@
         }
     }
 
-    public void topAppWindowChanged(boolean menuVisible) {
+    // TODO(b/117478341): Add multi-display support.
+    @Override
+    public void topAppWindowChanged(int displayId, boolean menuVisible) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED);
             mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0,
@@ -290,7 +296,9 @@
         }
     }
 
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+    // TODO(b/117478341): Add multi-display support.
+    @Override
+    public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
@@ -371,7 +379,9 @@
         }
     }
 
-    public void setWindowState(int window, int state) {
+    // TODO(b/117478341): Add multi-display support.
+    @Override
+    public void setWindowState(int displayId, int window, int state) {
         synchronized (mLock) {
             // don't coalesce these
             mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget();
@@ -385,7 +395,9 @@
         }
     }
 
-    public void appTransitionPending() {
+    // TODO(b/117478341): Add multi-display support.
+    @Override
+    public void appTransitionPending(int displayId) {
         appTransitionPending(false /* forced */);
     }
 
@@ -395,13 +407,17 @@
         }
     }
 
-    public void appTransitionCancelled() {
+    // TODO(b/117478341): Add multi-display support.
+    @Override
+    public void appTransitionCancelled(int displayId) {
         synchronized (mLock) {
             mHandler.sendEmptyMessage(MSG_APP_TRANSITION_CANCELLED);
         }
     }
 
-    public void appTransitionStarting(long startTime, long duration) {
+    // TODO(b/117478341): Add multi-display support.
+    @Override
+    public void appTransitionStarting(int displayId, long startTime, long duration) {
         appTransitionStarting(startTime, duration, false /* forced */);
     }
 
@@ -412,8 +428,9 @@
         }
     }
 
+    // TODO(b/117478341): Add multi-display support.
     @Override
-    public void appTransitionFinished() {
+    public void appTransitionFinished(int displayId) {
         synchronized (mLock) {
             mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 12a0cc8..3984405 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -24,7 +24,6 @@
 import android.view.Display;
 import android.view.IWallpaperVisibilityListener;
 import android.view.IWindowManager;
-import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.internal.statusbar.IStatusBarService;
@@ -165,23 +164,4 @@
         }
         mView.onDarkIntensityChange(darkIntensity);
     }
-
-    private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
-        @Override
-        public boolean onTouch(View v, MotionEvent ev) {
-            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-                // even though setting the systemUI visibility below will turn these views
-                // on, we need them to come up faster so that they can catch this motion
-                // event
-                applyLightsOut(false, false, false);
-
-                try {
-                    mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
-                            "LightsOutListener");
-                } catch (android.os.RemoteException ex) {
-                }
-            }
-            return false;
-        }
-    };
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 8ae3cd8..a4fe52d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -64,11 +66,12 @@
         verify(mCallbacks).removeIcon(eq(slot));
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testDisable() {
         int state1 = 14;
         int state2 = 42;
-        mCommandQueue.disable(state1, state2);
+        mCommandQueue.disable(DEFAULT_DISPLAY, state1, state2);
         waitForIdleSync();
         verify(mCallbacks).disable(eq(state1), eq(state2), eq(true));
     }
@@ -95,24 +98,27 @@
         verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testSetSystemUiVisibility() {
         Rect r = new Rect();
-        mCommandQueue.setSystemUiVisibility(1, 2, 3, 4, null, r);
+        mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r);
         waitForIdleSync();
         verify(mCallbacks).setSystemUiVisibility(eq(1), eq(2), eq(3), eq(4), eq(null), eq(r));
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testTopAppWindowChanged() {
-        mCommandQueue.topAppWindowChanged(true);
+        mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true);
         waitForIdleSync();
         verify(mCallbacks).topAppWindowChanged(eq(true));
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testShowImeButton() {
-        mCommandQueue.setImeWindowStatus(null, 1, 2, true);
+        mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
         waitForIdleSync();
         verify(mCallbacks).setImeWindowStatus(eq(null), eq(1), eq(2), eq(true));
     }
@@ -166,9 +172,10 @@
         verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testSetWindowState() {
-        mCommandQueue.setWindowState(1, 2);
+        mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
         waitForIdleSync();
         verify(mCallbacks).setWindowState(eq(1), eq(2));
     }
@@ -180,30 +187,34 @@
         verify(mCallbacks).showScreenPinningRequest(eq(1));
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testAppTransitionPending() {
-        mCommandQueue.appTransitionPending();
+        mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
         waitForIdleSync();
         verify(mCallbacks).appTransitionPending(eq(false));
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testAppTransitionCancelled() {
-        mCommandQueue.appTransitionCancelled();
+        mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
         waitForIdleSync();
         verify(mCallbacks).appTransitionCancelled();
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testAppTransitionStarting() {
-        mCommandQueue.appTransitionStarting(1, 2);
+        mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
         waitForIdleSync();
         verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L), eq(false));
     }
 
+    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testAppTransitionFinished() {
-        mCommandQueue.appTransitionFinished();
+        mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
         waitForIdleSync();
         verify(mCallbacks).appTransitionFinished();
     }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index e645b84..6e4c00e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.statusbar;
 
 import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
+import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.app.ActivityThread;
 import android.app.Notification;
@@ -25,6 +26,8 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -40,7 +43,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
-import android.view.Display;
+import android.util.SparseArray;
 
 import com.android.internal.R;
 import com.android.internal.statusbar.IStatusBar;
@@ -63,7 +66,7 @@
  * A note on locking:  We rely on the fact that calls onto mBar are oneway or
  * if they are local, that they just enqueue messages to not deadlock.
  */
-public class StatusBarManagerService extends IStatusBarService.Stub {
+public class StatusBarManagerService extends IStatusBarService.Stub implements DisplayListener {
     private static final String TAG = "StatusBarManagerService";
     private static final boolean SPEW = false;
 
@@ -79,24 +82,13 @@
     private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
     private GlobalActionsProvider.GlobalActionsListener mGlobalActionListener;
     private IBinder mSysUiVisToken = new Binder();
-    private int mDisabled1 = 0;
-    private int mDisabled2 = 0;
 
     private final Object mLock = new Object();
     private final DeathRecipient mDeathRecipient = new DeathRecipient();
-    // encompasses lights-out mode and other flags defined on View
-    private int mSystemUiVisibility = 0;
-    private int mFullscreenStackSysUiVisibility;
-    private int mDockedStackSysUiVisibility;
-    private final Rect mFullscreenStackBounds = new Rect();
-    private final Rect mDockedStackBounds = new Rect();
-    private boolean mMenuVisible = false;
-    private int mImeWindowVis = 0;
-    private int mImeBackDisposition;
-    private boolean mShowImeSwitcher;
-    private IBinder mImeToken = null;
     private int mCurrentUserId;
 
+    private SparseArray<UiState> mDisplayUiState = new SparseArray<>();
+
     private class DeathRecipient implements IBinder.DeathRecipient {
         public void binderDied() {
             mBar.asBinder().unlinkToDeath(this,0);
@@ -185,8 +177,29 @@
 
         LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
         LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider);
+
+        // We always have a default display.
+        final UiState state = new UiState();
+        mDisplayUiState.put(DEFAULT_DISPLAY, state);
+
+        final DisplayManager displayManager =
+                (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+        displayManager.registerDisplayListener(this, mHandler);
     }
 
+    @Override
+    public void onDisplayAdded(int displayId) {}
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        synchronized (mLock) {
+            mDisplayUiState.remove(displayId);
+        }
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {}
+
     /**
      * Private API used by NotificationManagerService.
      */
@@ -240,22 +253,14 @@
 
         @Override
         public void topAppWindowChanged(int displayId, boolean menuVisible) {
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
-                return;
-            }
-            StatusBarManagerService.this.topAppWindowChanged(menuVisible);
+            StatusBarManagerService.this.topAppWindowChanged(displayId, menuVisible);
         }
 
         @Override
         public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
                 int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds,
                 String cause) {
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
-                return;
-            }
-            StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis,
+            StatusBarManagerService.this.setSystemUiVisibility(displayId, vis, fullscreenStackVis,
                     dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
         }
 
@@ -272,13 +277,9 @@
         @Override
         public void appTransitionFinished(int displayId) {
             enforceStatusBarService();
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
-                return;
-            }
             if (mBar != null) {
                 try {
-                    mBar.appTransitionFinished();
+                    mBar.appTransitionFinished(displayId);
                 } catch (RemoteException ex) {}
             }
         }
@@ -374,39 +375,27 @@
 
         @Override
         public void setWindowState(int displayId, int window, int state) {
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
-                return;
-            }
             if (mBar != null) {
                 try {
-                    mBar.setWindowState(window, state);
+                    mBar.setWindowState(displayId, window, state);
                 } catch (RemoteException ex) {}
             }
         }
 
         @Override
         public void appTransitionPending(int displayId) {
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
-                return;
-            }
             if (mBar != null) {
                 try {
-                    mBar.appTransitionPending();
+                    mBar.appTransitionPending(displayId);
                 } catch (RemoteException ex) {}
             }
         }
 
         @Override
         public void appTransitionCancelled(int displayId) {
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
-                return;
-            }
             if (mBar != null) {
                 try {
-                    mBar.appTransitionCancelled();
+                    mBar.appTransitionCancelled(displayId);
                 } catch (RemoteException ex) {}
             }
         }
@@ -414,14 +403,10 @@
         @Override
         public void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
                 long statusBarAnimationsDuration) {
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
-                return;
-            }
             if (mBar != null) {
                 try {
                     mBar.appTransitionStarting(
-                            statusBarAnimationsStartTime, statusBarAnimationsDuration);
+                            displayId, statusBarAnimationsStartTime, statusBarAnimationsDuration);
                 } catch (RemoteException ex) {}
             }
         }
@@ -449,6 +434,7 @@
             return false;
         }
 
+        // TODO(b/118592525): support it per display if necessary.
         @Override
         public void onProposedRotationChanged(int rotation, boolean isValid) {
             if (mBar != null){
@@ -462,7 +448,9 @@
     private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
         @Override
         public boolean isGlobalActionsDisabled() {
-            return (mDisabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
+            // TODO(b/118592525): support global actions for multi-display.
+            final int disabled2 = mDisplayUiState.get(DEFAULT_DISPLAY).getDisabled2();
+            return (disabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
         }
 
         @Override
@@ -664,20 +652,23 @@
         }
     }
 
+    // TODO(b/117478341): make it aware of multi-display if needed.
     @Override
     public void disable(int what, IBinder token, String pkg) {
         disableForUser(what, token, pkg, mCurrentUserId);
     }
 
+    // TODO(b/117478341): make it aware of multi-display if needed.
     @Override
     public void disableForUser(int what, IBinder token, String pkg, int userId) {
         enforceStatusBar();
 
         synchronized (mLock) {
-            disableLocked(userId, what, token, pkg, 1);
+            disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1);
         }
     }
 
+    // TODO(b/117478341): make it aware of multi-display if needed.
     /**
      * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
      * To re-enable everything, pass {@link #DISABLE_NONE}.
@@ -689,6 +680,7 @@
         disable2ForUser(what, token, pkg, mCurrentUserId);
     }
 
+    // TODO(b/117478341): make it aware of multi-display if needed.
     /**
      * Disable additional status bar features for a given user. Pass the bitwise-or of the
      * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}.
@@ -700,11 +692,12 @@
         enforceStatusBar();
 
         synchronized (mLock) {
-            disableLocked(userId, what, token, pkg, 2);
+            disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2);
         }
     }
 
-    private void disableLocked(int userId, int what, IBinder token, String pkg, int whichFlag) {
+    private void disableLocked(int displayId, int userId, int what, IBinder token, String pkg,
+            int whichFlag) {
         // It's important that the the callback and the call to mBar get done
         // in the same order when multiple threads are calling this function
         // so they are paired correctly.  The messages on the handler will be
@@ -723,22 +716,19 @@
                 disabledData += "    ([" + i + "] " + tok + "), ";
             }
             disabledData += " }";
-            Log.d(TAG, "disabledlocked (b/113914868): net1=" + net1 + ", mDisabled1=" + mDisabled1
-                    + ", token=" + token + ", mDisableRecords=" + mDisableRecords.size() + " => "
-                    + disabledData);
-        }
+            final UiState state = getUiState(displayId);
 
-        if (net1 != mDisabled1 || net2 != mDisabled2) {
-            mDisabled1 = net1;
-            mDisabled2 = net2;
-            mHandler.post(new Runnable() {
-                    public void run() {
-                        mNotificationDelegate.onSetDisabled(net1);
-                    }
-                });
+            Log.d(TAG, "disabledlocked (b/113914868): displayId=" + displayId + "net1=" + net1
+                    + ", mDisabled1=" + state.mDisabled1 + ", token=" + token
+                    + ", mDisableRecords=" + mDisableRecords.size() + " => " + disabledData);
+        }
+        final UiState state = getUiState(displayId);
+        if (state.disableEquals(net1, net2)) {
+            state.setDisabled(net1, net2);
+            mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
             if (mBar != null) {
                 try {
-                    mBar.disable(net1, net2);
+                    mBar.disable(displayId, net1, net2);
                 } catch (RemoteException ex) {
                 }
             }
@@ -808,26 +798,27 @@
      * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
      * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
      */
-    private void topAppWindowChanged(final boolean menuVisible) {
+    private void topAppWindowChanged(int displayId, final boolean menuVisible) {
         enforceStatusBar();
 
-        if (SPEW) Slog.d(TAG, (menuVisible?"showing":"hiding") + " MENU key");
-
+        if (SPEW) {
+            Slog.d(TAG, "display#" + displayId + ": "
+                    + (menuVisible ? "showing" : "hiding") + " MENU key");
+        }
         synchronized(mLock) {
-            mMenuVisible = menuVisible;
-            mHandler.post(new Runnable() {
-                public void run() {
-                    if (mBar != null) {
-                        try {
-                            mBar.topAppWindowChanged(menuVisible);
-                        } catch (RemoteException ex) {
-                        }
+            getUiState(displayId).setMenuVisible(menuVisible);
+            mHandler.post(() -> {
+                if (mBar != null) {
+                    try {
+                        mBar.topAppWindowChanged(displayId, menuVisible);
+                    } catch (RemoteException ex) {
                     }
                 }
             });
         }
     }
 
+    // TODO(b/117478341): support back button change when IME is showing on a external display.
     @Override
     public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
             final boolean showImeSwitcher) {
@@ -841,39 +832,42 @@
             // In case of IME change, we need to call up setImeWindowStatus() regardless of
             // mImeWindowVis because mImeWindowVis may not have been set to false when the
             // previous IME was destroyed.
-            mImeWindowVis = vis;
-            mImeBackDisposition = backDisposition;
-            mImeToken = token;
-            mShowImeSwitcher = showImeSwitcher;
-            mHandler.post(new Runnable() {
-                public void run() {
-                    if (mBar != null) {
-                        try {
-                            mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher);
-                        } catch (RemoteException ex) {
-                        }
-                    }
-                }
+            // TODO(b/117478341): support back button change when IME is showing on a external
+            // display.
+            getUiState(DEFAULT_DISPLAY)
+                    .setImeWindowState(vis, backDisposition, showImeSwitcher, token);
+
+            mHandler.post(() -> {
+                if (mBar == null) return;
+                try {
+                    // TODO(b/117478341): support back button change when IME is showing on a
+                    // external display.
+                    mBar.setImeWindowStatus(
+                            DEFAULT_DISPLAY, token, vis, backDisposition, showImeSwitcher);
+                } catch (RemoteException ex) { }
             });
         }
     }
 
     @Override
-    public void setSystemUiVisibility(int vis, int mask, String cause) {
-        setSystemUiVisibility(vis, 0, 0, mask, mFullscreenStackBounds, mDockedStackBounds, cause);
+    public void setSystemUiVisibility(int displayId, int vis, int mask, String cause) {
+        final UiState state = getUiState(displayId);
+        setSystemUiVisibility(displayId, vis, 0, 0, mask,
+                state.mFullscreenStackBounds, state.mDockedStackBounds, cause);
     }
 
-    private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
-            Rect fullscreenBounds, Rect dockedBounds, String cause) {
+    private void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+            int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, String cause) {
         // also allows calls from window manager which is in this process.
         enforceStatusBarService();
 
         if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
 
         synchronized (mLock) {
-            updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask,
+            updateUiVisibilityLocked(displayId, vis, fullscreenStackVis, dockedStackVis, mask,
                     fullscreenBounds, dockedBounds);
             disableLocked(
+                    displayId,
                     mCurrentUserId,
                     vis & StatusBarManager.DISABLE_MASK,
                     mSysUiVisToken,
@@ -881,30 +875,107 @@
         }
     }
 
-    private void updateUiVisibilityLocked(final int vis,
+    private void updateUiVisibilityLocked(final int displayId, final int vis,
             final int fullscreenStackVis, final int dockedStackVis, final int mask,
             final Rect fullscreenBounds, final Rect dockedBounds) {
-        if (mSystemUiVisibility != vis
-                || mFullscreenStackSysUiVisibility != fullscreenStackVis
-                || mDockedStackSysUiVisibility != dockedStackVis
-                || !mFullscreenStackBounds.equals(fullscreenBounds)
-                || !mDockedStackBounds.equals(dockedBounds)) {
+        final UiState state = getUiState(displayId);
+        if (!state.systemUiStateEquals(vis, fullscreenStackVis, dockedStackVis,
+                fullscreenBounds, dockedBounds)) {
+            state.setSystemUiState(vis, fullscreenStackVis, dockedStackVis, fullscreenBounds,
+                    dockedBounds);
+            mHandler.post(() -> {
+                if (mBar != null) {
+                    try {
+                        mBar.setSystemUiVisibility(displayId, vis, fullscreenStackVis,
+                                dockedStackVis, mask, fullscreenBounds, dockedBounds);
+                    } catch (RemoteException ex) {
+                        Log.w(TAG, "Can not get StatusBar!");
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * @return {@link UiState} specified by {@code displayId}.
+     *
+     * <p>
+     *   Note: If {@link UiState} specified by {@code displayId} does not exist, {@link UiState}
+     *   will be allocated and {@code mDisplayUiState} will be updated accordingly.
+     * <p/>
+     */
+    private UiState getUiState(int displayId) {
+        UiState state = mDisplayUiState.get(displayId);
+        if (state == null) {
+            state = new UiState();
+            mDisplayUiState.put(displayId, state);
+        }
+        return state;
+    }
+
+    private class UiState {
+        private int mSystemUiVisibility = 0;
+        private int mFullscreenStackSysUiVisibility = 0;
+        private int mDockedStackSysUiVisibility = 0;
+        private final Rect mFullscreenStackBounds = new Rect();
+        private final Rect mDockedStackBounds = new Rect();
+        private boolean mMenuVisible = false;
+        private int mDisabled1 = 0;
+        private int mDisabled2 = 0;
+        private int mImeWindowVis = 0;
+        private int mImeBackDisposition = 0;
+        private boolean mShowImeSwitcher = false;
+        private IBinder mImeToken = null;
+
+        private int getDisabled1() {
+            return mDisabled1;
+        }
+
+        private int getDisabled2() {
+            return mDisabled2;
+        }
+
+        private void setDisabled(int disabled1, int disabled2) {
+            mDisabled1 = disabled1;
+            mDisabled2 = disabled2;
+        }
+
+        private boolean isMenuVisible() {
+            return mMenuVisible;
+        }
+
+        private void setMenuVisible(boolean menuVisible) {
+            mMenuVisible = menuVisible;
+        }
+
+        private boolean disableEquals(int disabled1, int disabled2) {
+            return mDisabled1 == disabled1 && mDisabled2 == disabled2;
+        }
+
+        private void setSystemUiState(final int vis, final int fullscreenStackVis,
+                final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds) {
             mSystemUiVisibility = vis;
             mFullscreenStackSysUiVisibility = fullscreenStackVis;
             mDockedStackSysUiVisibility = dockedStackVis;
             mFullscreenStackBounds.set(fullscreenBounds);
             mDockedStackBounds.set(dockedBounds);
-            mHandler.post(new Runnable() {
-                    public void run() {
-                        if (mBar != null) {
-                            try {
-                                mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
-                                        mask, fullscreenBounds, dockedBounds);
-                            } catch (RemoteException ex) {
-                            }
-                        }
-                    }
-                });
+        }
+
+        private boolean systemUiStateEquals(final int vis, final int fullscreenStackVis,
+                final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds) {
+            return mSystemUiVisibility == vis
+                && mFullscreenStackSysUiVisibility == fullscreenStackVis
+                && mDockedStackSysUiVisibility == dockedStackVis
+                && mFullscreenStackBounds.equals(fullscreenBounds)
+                && mDockedStackBounds.equals(dockedBounds);
+        }
+
+        private void setImeWindowState(final int vis, final int backDisposition,
+                final boolean showImeSwitcher, final IBinder token) {
+            mImeWindowVis = vis;
+            mImeBackDisposition = backDisposition;
+            mShowImeSwitcher = showImeSwitcher;
+            mImeToken = token;
         }
     }
 
@@ -939,6 +1010,7 @@
     // ================================================================================
     // Callbacks from the status bar service.
     // ================================================================================
+    // TODO(b/118592525): refactor it as an IStatusBar API.
     @Override
     public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
             List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
@@ -956,18 +1028,21 @@
             }
         }
         synchronized (mLock) {
+            // TODO(b/118592525): Currently, status bar only works on the default display.
+            // Make it aware of multi-display if needed.
+            final UiState state = mDisplayUiState.get(DEFAULT_DISPLAY);
             switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
-            switches[1] = mSystemUiVisibility;
-            switches[2] = mMenuVisible ? 1 : 0;
-            switches[3] = mImeWindowVis;
-            switches[4] = mImeBackDisposition;
-            switches[5] = mShowImeSwitcher ? 1 : 0;
+            switches[1] = state.mSystemUiVisibility;
+            switches[2] = state.mMenuVisible ? 1 : 0;
+            switches[3] = state.mImeWindowVis;
+            switches[4] = state.mImeBackDisposition;
+            switches[5] = state.mShowImeSwitcher ? 1 : 0;
             switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
-            switches[7] = mFullscreenStackSysUiVisibility;
-            switches[8] = mDockedStackSysUiVisibility;
-            binders.add(mImeToken);
-            fullscreenStackBounds.set(mFullscreenStackBounds);
-            dockedStackBounds.set(mDockedStackBounds);
+            switches[7] = state.mFullscreenStackSysUiVisibility;
+            switches[8] = state.mDockedStackSysUiVisibility;
+            binders.add(state.mImeToken);
+            fullscreenStackBounds.set(state.mFullscreenStackBounds);
+            dockedStackBounds.set(state.mDockedStackBounds);
         }
     }
 
@@ -1309,8 +1384,13 @@
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
         synchronized (mLock) {
-            pw.println("  mDisabled1=0x" + Integer.toHexString(mDisabled1));
-            pw.println("  mDisabled2=0x" + Integer.toHexString(mDisabled2));
+            for (int i = 0; i < mDisplayUiState.size(); i++) {
+                final int key = mDisplayUiState.keyAt(i);
+                final UiState state = mDisplayUiState.get(key);
+                pw.println("  displayId=" + key);
+                pw.println("    mDisabled1=0x" + Integer.toHexString(state.getDisabled1()));
+                pw.println("    mDisabled2=0x" + Integer.toHexString(state.getDisabled2()));
+            }
             final int N = mDisableRecords.size();
             pw.println("  mDisableRecords.size=" + N);
             for (int i=0; i<N; i++) {