Use display context to inflate navbar on external display

- Disable rotation suggestion button if the navbar is on
  non-default display because there is no accelerometer sensor.
- Avoid leakage by removing navbar fragment from fragment
  host when display is removed.

Bug: 117746225
Bug: 117744614
Test: atest SystemUITests
Test: manual - create a virtual display with system decoration.
      The navbar on the virtual display should not change when
      rotating or changing density of default display.
      And after releasing the display, use command "dumpsys
      activity service com.android.systemui/.SystemUIService |
      grep NavigationBarFragment" to check the number of instances.

Change-Id: Icdc8634628ace21395b7eb9d77c6b1067850d1b2
diff --git a/packages/SystemUI/res/layout/navigation_bar_window.xml b/packages/SystemUI/res/layout/navigation_bar_window.xml
index 6fa46d4..f98cbd8 100644
--- a/packages/SystemUI/res/layout/navigation_bar_window.xml
+++ b/packages/SystemUI/res/layout/navigation_bar_window.xml
@@ -20,6 +20,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/navigation_bar_frame"
+    android:theme="@style/Theme.SystemUI"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index fbcf068..5e6d272 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -296,7 +296,7 @@
                 new WakefulnessLifecycle());
 
         mProviders.put(FragmentService.class, () ->
-                new FragmentService(mContext));
+                new FragmentService());
 
         mProviders.put(ExtensionController.class, () ->
                 new ExtensionControllerImpl(mContext));
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 0ed1cd1..779a86c 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -59,11 +59,11 @@
     private FragmentController mFragments;
     private FragmentLifecycleCallbacks mLifecycleCallbacks;
 
-    FragmentHostManager(Context context, FragmentService manager, View rootView) {
-        mContext = context;
+    FragmentHostManager(FragmentService manager, View rootView) {
+        mContext = rootView.getContext();
         mManager = manager;
         mRootView = rootView;
-        mConfigChanges.applyNewConfig(context.getResources());
+        mConfigChanges.applyNewConfig(mContext.getResources());
         createFragmentHost(null);
     }
 
@@ -203,6 +203,10 @@
         }
     }
 
+    public static void removeAndDestroy(View view) {
+        Dependency.get(FragmentService.class).removeAndDestroy(view);
+    }
+
     class HostCallbacks extends FragmentHostCallback<FragmentHostManager> {
         public HostCallbacks() {
             super(mContext, FragmentHostManager.this.mHandler, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index f9bf4f5..bf7d629 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -14,18 +14,13 @@
 
 package com.android.systemui.fragments;
 
-import android.content.Context;
 import android.content.res.Configuration;
-import android.os.Bundle;
 import android.os.Handler;
 import android.util.ArrayMap;
-import android.util.Log;
 import android.view.View;
 
 import com.android.systemui.ConfigurationChangedReceiver;
 import com.android.systemui.Dumpable;
-import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIApplication;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -40,11 +35,6 @@
 
     private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>();
     private final Handler mHandler = new Handler();
-    private final Context mContext;
-
-    public FragmentService(Context context) {
-        mContext = context;
-    }
 
     public FragmentHostManager getFragmentHostManager(View view) {
         View root = view.getRootView();
@@ -56,6 +46,13 @@
         return state.getFragmentHostManager();
     }
 
+    public void removeAndDestroy(View view) {
+        final FragmentHostState state = mHosts.remove(view.getRootView());
+        if (state != null) {
+            state.mFragmentHostManager.destroy();
+        }
+    }
+
     public void destroyAll() {
         for (FragmentHostState state : mHosts.values()) {
             state.mFragmentHostManager.destroy();
@@ -84,7 +81,7 @@
 
         public FragmentHostState(View view) {
             mView = view;
-            mFragmentHostManager = new FragmentHostManager(mContext, FragmentService.this, mView);
+            mFragmentHostManager = new FragmentHostManager(FragmentService.this, mView);
         }
 
         public void sendConfigurationChange(Configuration newConfig) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 4406b14..0cf1b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -144,6 +144,7 @@
 
     private OverviewProxyService mOverviewProxyService;
 
+    private boolean mIsOnDefaultDisplay = true;
     public boolean mHomeBlockedThisTouch;
 
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
@@ -241,6 +242,11 @@
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         mNavigationBarView = (NavigationBarView) view;
+        final Display display = view.getDisplay();
+        // It may not have display when running unit test.
+        if (display != null) {
+            mIsOnDefaultDisplay = display.getDisplayId() == Display.DEFAULT_DISPLAY;
+        }
 
         mNavigationBarView.setComponents(mStatusBar.getPanel());
         mNavigationBarView.setDisabledFlags(mDisabledFlags1);
@@ -253,8 +259,6 @@
         prepareNavigationBarView();
         checkNavBarModes();
 
-        setDisabled2Flags(mDisabledFlags2);
-
         IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_SCREEN_ON);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
@@ -262,16 +266,23 @@
         notifyNavigationBarScreenOn();
         mOverviewProxyService.addCallback(mOverviewProxyListener);
 
-        RotationContextButton rotationButton = mNavigationBarView.getRotateSuggestionButton();
-        rotationButton.setListener(mRotationButtonListener);
-        rotationButton.addRotationCallback(mRotationWatcher);
+        // Currently there is no accelerometer sensor on non-default display.
+        if (mIsOnDefaultDisplay) {
+            final RotationContextButton rotationButton =
+                    mNavigationBarView.getRotateSuggestionButton();
+            rotationButton.setListener(mRotationButtonListener);
+            rotationButton.addRotationCallback(mRotationWatcher);
 
-        // Reset user rotation pref to match that of the WindowManager if starting in locked mode
-        // This will automatically happen when switching from auto-rotate to locked mode
-        if (rotationButton.isRotationLocked()) {
-            final int winRotation = mWindowManager.getDefaultDisplay().getRotation();
-            rotationButton.setRotationLockedAtAngle(winRotation);
+            // Reset user rotation pref to match that of the WindowManager if starting in locked
+            // mode. This will automatically happen when switching from auto-rotate to locked mode.
+            if (display != null && rotationButton.isRotationLocked()) {
+                final int winRotation = display.getRotation();
+                rotationButton.setRotationLockedAtAngle(winRotation);
+            }
+        } else {
+            mDisabledFlags2 |= StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS;
         }
+        setDisabled2Flags(mDisabledFlags2);
     }
 
     @Override
@@ -389,7 +400,7 @@
 
     @Override
     public void onRotationProposal(final int rotation, boolean isValid) {
-        final int winRotation = mWindowManager.getDefaultDisplay().getRotation();
+        final int winRotation = mNavigationBarView.getDisplay().getRotation();
         final boolean rotateSuggestionsDisabled = RotationContextButton
                 .hasDisable2RotateSuggestionFlag(mDisabledFlags2);
         if (RotationContextButton.DEBUG_ROTATION) {
@@ -477,10 +488,13 @@
             updateScreenPinningGestures();
         }
 
-        final int masked2 = state2 & (StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS);
-        if (masked2 != mDisabledFlags2) {
-            mDisabledFlags2 = masked2;
-            setDisabled2Flags(masked2);
+        // Only default display supports rotation suggestions.
+        if (mIsOnDefaultDisplay) {
+            final int masked2 = state2 & (StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS);
+            if (masked2 != mDisabledFlags2) {
+                mDisabledFlags2 = masked2;
+                setDisabled2Flags(masked2);
+            }
         }
     }
 
@@ -881,13 +895,23 @@
         if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
         if (navigationBarView == null) return null;
 
+        final NavigationBarFragment fragment = new NavigationBarFragment();
+        navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+            @Override
+            public void onViewAttachedToWindow(View v) {
+                final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
+                fragmentHost.getFragmentManager().beginTransaction()
+                        .replace(R.id.navigation_bar_frame, fragment, TAG)
+                        .commit();
+                fragmentHost.addTagListener(TAG, listener);
+            }
+
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+                FragmentHostManager.removeAndDestroy(v);
+            }
+        });
         context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
-        FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView);
-        NavigationBarFragment fragment = new NavigationBarFragment();
-        fragmentHost.getFragmentManager().beginTransaction()
-                .replace(R.id.navigation_bar_frame, fragment, TAG)
-                .commit();
-        fragmentHost.addTagListener(TAG, listener);
         return navigationBarView;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 2c3c27f..b43bbdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -264,8 +264,7 @@
     public NavigationBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mDisplay = ((WindowManager) context.getSystemService(
-                Context.WINDOW_SERVICE)).getDefaultDisplay();
+        mDisplay = context.getDisplay();
 
         mVertical = false;
         mLongClickableAccessibilityButton = false;