• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.car.systembar;
18 
19 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
20 
21 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
22 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
23 
24 import android.app.StatusBarManager.Disable2Flags;
25 import android.app.StatusBarManager.DisableFlags;
26 import android.app.UiModeManager;
27 import android.content.Context;
28 import android.content.res.Configuration;
29 import android.graphics.Rect;
30 import android.inputmethodservice.InputMethodService;
31 import android.os.IBinder;
32 import android.os.RemoteException;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.view.WindowInsets;
36 import android.view.WindowInsets.Type.InsetsType;
37 import android.view.WindowInsetsController;
38 import android.view.WindowManager;
39 
40 import androidx.annotation.VisibleForTesting;
41 
42 import com.android.internal.statusbar.IStatusBarService;
43 import com.android.internal.statusbar.LetterboxDetails;
44 import com.android.internal.statusbar.RegisterStatusBarResult;
45 import com.android.internal.view.AppearanceRegion;
46 import com.android.systemui.CoreStartable;
47 import com.android.systemui.R;
48 import com.android.systemui.car.CarDeviceProvisionedController;
49 import com.android.systemui.car.CarDeviceProvisionedListener;
50 import com.android.systemui.car.hvac.HvacController;
51 import com.android.systemui.car.users.CarSystemUIUserUtil;
52 import com.android.systemui.dagger.qualifiers.Main;
53 import com.android.systemui.dagger.qualifiers.UiBackground;
54 import com.android.systemui.plugins.DarkIconDispatcher;
55 import com.android.systemui.settings.DisplayTracker;
56 import com.android.systemui.shared.system.TaskStackChangeListener;
57 import com.android.systemui.shared.system.TaskStackChangeListeners;
58 import com.android.systemui.statusbar.AutoHideUiElement;
59 import com.android.systemui.statusbar.CommandQueue;
60 import com.android.systemui.statusbar.phone.AutoHideController;
61 import com.android.systemui.statusbar.phone.BarTransitions;
62 import com.android.systemui.statusbar.phone.LightBarController;
63 import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
64 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
65 import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher;
66 import com.android.systemui.statusbar.policy.ConfigurationController;
67 import com.android.systemui.statusbar.policy.KeyguardStateController;
68 import com.android.systemui.util.concurrency.DelayableExecutor;
69 import com.android.systemui.wm.MDSystemBarsController;
70 
71 import dagger.Lazy;
72 
73 import java.io.PrintWriter;
74 import java.util.ArrayList;
75 import java.util.Optional;
76 import java.util.concurrent.Executor;
77 
78 import javax.inject.Inject;
79 
80 /** Navigation bars customized for the automotive use case. */
81 public class CarSystemBar implements CoreStartable, CommandQueue.Callbacks,
82         ConfigurationController.ConfigurationListener,
83         MDSystemBarsController.Listener {
84     private final Context mContext;
85     private final CarSystemBarController mCarSystemBarController;
86     private final SysuiDarkIconDispatcher mStatusBarIconController;
87     private final WindowManager mWindowManager;
88     private final CarDeviceProvisionedController mCarDeviceProvisionedController;
89     private final CommandQueue mCommandQueue;
90     private final AutoHideController mAutoHideController;
91     private final ButtonSelectionStateListener mButtonSelectionStateListener;
92     private final DelayableExecutor mExecutor;
93     private final Executor mUiBgExecutor;
94     private final IStatusBarService mBarService;
95     private final DisplayTracker mDisplayTracker;
96     private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy;
97     private final Lazy<PhoneStatusBarPolicy> mIconPolicyLazy;
98     private final HvacController mHvacController;
99 
100     private UiModeManager mUiModeManager;
101 
102     private final int mDisplayId;
103     private final SystemBarConfigs mSystemBarConfigs;
104 
105     private StatusBarSignalPolicy mSignalPolicy;
106 
107     // If the nav bar should be hidden when the soft keyboard is visible.
108     private boolean mHideTopBarForKeyboard;
109     private boolean mHideLeftBarForKeyboard;
110     private boolean mHideRightBarForKeyboard;
111     private boolean mHideBottomBarForKeyboard;
112 
113     private boolean mBottomNavBarVisible;
114 
115     // Nav bar views.
116     private ViewGroup mTopSystemBarWindow;
117     private ViewGroup mBottomSystemBarWindow;
118     private ViewGroup mLeftSystemBarWindow;
119     private ViewGroup mRightSystemBarWindow;
120     private CarSystemBarView mTopSystemBarView;
121     private CarSystemBarView mBottomSystemBarView;
122     private CarSystemBarView mLeftSystemBarView;
123     private CarSystemBarView mRightSystemBarView;
124 
125     // To be attached to the navigation bars such that they can close the notification panel if
126     // it's open.
127     private boolean mDeviceIsSetUpForUser = true;
128     private boolean mIsUserSetupInProgress = false;
129 
130     private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
131     @BarTransitions.TransitionMode
132     private int mStatusBarMode;
133     @BarTransitions.TransitionMode
134     private int mSystemBarMode;
135     private boolean mStatusBarTransientShown;
136     private boolean mNavBarTransientShown;
137 
138     private boolean mIsUiModeNight = false;
139     private MDSystemBarsController mMDSystemBarsController;
140 
141     @Inject
CarSystemBar(Context context, CarSystemBarController carSystemBarController, LightBarController lightBarController, DarkIconDispatcher darkIconDispatcher, WindowManager windowManager, CarDeviceProvisionedController deviceProvisionedController, CommandQueue commandQueue, AutoHideController autoHideController, ButtonSelectionStateListener buttonSelectionStateListener, @Main DelayableExecutor mainExecutor, @UiBackground Executor uiBgExecutor, IStatusBarService barService, Lazy<KeyguardStateController> keyguardStateControllerLazy, Lazy<PhoneStatusBarPolicy> iconPolicyLazy, HvacController hvacController, StatusBarSignalPolicy signalPolicy, SystemBarConfigs systemBarConfigs, ConfigurationController configurationController, DisplayTracker displayTracker, Optional<MDSystemBarsController> mdSystemBarsController )142     public CarSystemBar(Context context,
143             CarSystemBarController carSystemBarController,
144             // TODO(b/156052638): Should not need to inject LightBarController
145             LightBarController lightBarController,
146             DarkIconDispatcher darkIconDispatcher,
147             WindowManager windowManager,
148             CarDeviceProvisionedController deviceProvisionedController,
149             CommandQueue commandQueue,
150             AutoHideController autoHideController,
151             ButtonSelectionStateListener buttonSelectionStateListener,
152             @Main DelayableExecutor mainExecutor,
153             @UiBackground Executor uiBgExecutor,
154             IStatusBarService barService,
155             Lazy<KeyguardStateController> keyguardStateControllerLazy,
156             Lazy<PhoneStatusBarPolicy> iconPolicyLazy,
157             HvacController hvacController,
158             StatusBarSignalPolicy signalPolicy,
159             SystemBarConfigs systemBarConfigs,
160             ConfigurationController configurationController,
161             DisplayTracker displayTracker,
162             Optional<MDSystemBarsController> mdSystemBarsController
163     ) {
164         mContext = context;
165         mCarSystemBarController = carSystemBarController;
166         mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
167         mWindowManager = windowManager;
168         mCarDeviceProvisionedController = deviceProvisionedController;
169         mCommandQueue = commandQueue;
170         mAutoHideController = autoHideController;
171         mButtonSelectionStateListener = buttonSelectionStateListener;
172         mExecutor = mainExecutor;
173         mUiBgExecutor = uiBgExecutor;
174         mBarService = barService;
175         mKeyguardStateControllerLazy = keyguardStateControllerLazy;
176         mIconPolicyLazy = iconPolicyLazy;
177         mHvacController = hvacController;
178         mSystemBarConfigs = systemBarConfigs;
179         mSignalPolicy = signalPolicy;
180         mDisplayId = context.getDisplayId();
181         mUiModeManager = mContext.getSystemService(UiModeManager.class);
182         mDisplayTracker = displayTracker;
183         mIsUiModeNight = mContext.getResources().getConfiguration().isNightModeActive();
184         configurationController.addCallback(this);
185         mMDSystemBarsController = mdSystemBarsController.orElse(null);
186     }
187 
188     @Override
start()189     public void start() {
190         // Set initial state.
191         mHideTopBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.TOP);
192         mHideBottomBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(
193                 SystemBarConfigs.BOTTOM);
194         mHideLeftBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.LEFT);
195         mHideRightBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(
196                 SystemBarConfigs.RIGHT);
197 
198         mBottomNavBarVisible = false;
199 
200         // Connect into the status bar manager service
201         mCommandQueue.addCallback(this);
202 
203         RegisterStatusBarResult result = null;
204         //Register only for Primary User.
205         if (!CarSystemUIUserUtil.isSecondaryMUMDSystemUI()) {
206             try {
207                 result = mBarService.registerStatusBar(mCommandQueue);
208             } catch (RemoteException ex) {
209                 ex.rethrowFromSystemServer();
210             }
211         } else if (mMDSystemBarsController != null) {
212             mMDSystemBarsController.addListener(this);
213         }
214 
215         if (result != null) {
216             onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
217                     result.mNavbarColorManagedByIme, result.mBehavior,
218                     result.mRequestedVisibleTypes,
219                     result.mPackageName, result.mLetterboxDetails);
220 
221             // StatusBarManagerService has a back up of IME token and it's restored here.
222             setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
223                     result.mImeBackDisposition, result.mShowImeSwitcher);
224 
225             // Set up the initial icon state
226             int numIcons = result.mIcons.size();
227             for (int i = 0; i < numIcons; i++) {
228                 mCommandQueue.setIcon(result.mIcons.keyAt(i), result.mIcons.valueAt(i));
229             }
230         }
231 
232         mAutoHideController.setStatusBar(new AutoHideUiElement() {
233             @Override
234             public void synchronizeState() {
235                 // No op.
236             }
237 
238             @Override
239             public boolean isVisible() {
240                 return mStatusBarTransientShown;
241             }
242 
243             @Override
244             public void hide() {
245                 clearTransient();
246             }
247         });
248 
249         mAutoHideController.setNavigationBar(new AutoHideUiElement() {
250             @Override
251             public void synchronizeState() {
252                 // No op.
253             }
254 
255             @Override
256             public boolean isVisible() {
257                 return mNavBarTransientShown;
258             }
259 
260             @Override
261             public void hide() {
262                 clearTransient();
263             }
264         });
265 
266         mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup();
267         mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress();
268         mCarDeviceProvisionedController.addCallback(
269                 new CarDeviceProvisionedListener() {
270                     @Override
271                     public void onUserSetupInProgressChanged() {
272                         mExecutor.execute(() -> restartNavBarsIfNecessary());
273                     }
274 
275                     @Override
276                     public void onUserSetupChanged() {
277                         mExecutor.execute(() -> restartNavBarsIfNecessary());
278                     }
279 
280                     @Override
281                     public void onUserSwitched() {
282                         mExecutor.execute(() -> restartNavBarsIfNecessary());
283                     }
284                 });
285 
286         createSystemBar(result);
287 
288         TaskStackChangeListeners.getInstance().registerTaskStackListener(
289                 mButtonSelectionStateListener);
290         TaskStackChangeListeners.getInstance().registerTaskStackListener(
291                 new TaskStackChangeListener() {
292             @Override
293             public void onLockTaskModeChanged(int mode) {
294                 mCarSystemBarController.refreshSystemBar();
295             }
296         });
297 
298         // Lastly, call to the icon policy to install/update all the icons.
299         // Must be called on the main thread due to the use of observeForever() in
300         // mIconPolicy.init().
301         mExecutor.execute(() -> {
302             mIconPolicyLazy.get().init();
303         });
304     }
305 
restartNavBarsIfNecessary()306     private void restartNavBarsIfNecessary() {
307         boolean currentUserSetup = mCarDeviceProvisionedController.isCurrentUserSetup();
308         boolean currentUserSetupInProgress = mCarDeviceProvisionedController
309                 .isCurrentUserSetupInProgress();
310         if (mIsUserSetupInProgress != currentUserSetupInProgress
311                 || mDeviceIsSetUpForUser != currentUserSetup) {
312             mDeviceIsSetUpForUser = currentUserSetup;
313             mIsUserSetupInProgress = currentUserSetupInProgress;
314             restartNavBars();
315         }
316     }
317 
318     /**
319      * Remove all content from navbars and rebuild them. Used to allow for different nav bars
320      * before and after the device is provisioned. . Also for change of density and font size.
321      */
restartNavBars()322     private void restartNavBars() {
323         // remove and reattach all components such that we don't keep a reference to unused ui
324         // elements
325         mCarSystemBarController.removeAll();
326 
327         if (mTopSystemBarWindow != null) {
328             mTopSystemBarWindow.removeAllViews();
329             mHvacController.unregisterViews(mTopSystemBarView);
330             mTopSystemBarView = null;
331         }
332 
333         if (mBottomSystemBarWindow != null) {
334             mBottomSystemBarWindow.removeAllViews();
335             mHvacController.unregisterViews(mBottomSystemBarView);
336             mBottomSystemBarView = null;
337         }
338 
339         if (mLeftSystemBarWindow != null) {
340             mLeftSystemBarWindow.removeAllViews();
341             mHvacController.unregisterViews(mLeftSystemBarView);
342             mLeftSystemBarView = null;
343         }
344 
345         if (mRightSystemBarWindow != null) {
346             mRightSystemBarWindow.removeAllViews();
347             mHvacController.unregisterViews(mRightSystemBarView);
348             mRightSystemBarView = null;
349         }
350 
351         buildNavBarContent();
352         // If the UI was rebuilt (day/night change or user change) while the keyguard was up we need
353         // to correctly respect that state.
354         if (mKeyguardStateControllerLazy.get().isShowing()) {
355             mCarSystemBarController.showAllKeyguardButtons(isDeviceSetupForUser());
356         } else {
357             mCarSystemBarController.showAllNavigationButtons(isDeviceSetupForUser());
358         }
359 
360         // Upon restarting the Navigation Bar, CarFacetButtonController should immediately apply the
361         // selection state that reflects the current task stack.
362         mButtonSelectionStateListener.onTaskStackChanged();
363     }
364 
isDeviceSetupForUser()365     private boolean isDeviceSetupForUser() {
366         return mDeviceIsSetUpForUser && !mIsUserSetupInProgress;
367     }
368 
createSystemBar(RegisterStatusBarResult result)369     private void createSystemBar(RegisterStatusBarResult result) {
370         buildNavBarWindows();
371         buildNavBarContent();
372         attachNavBarWindows();
373 
374         // Try setting up the initial state of the nav bar if applicable.
375         if (result != null) {
376             setImeWindowStatus(mDisplayTracker.getDefaultDisplayId(), result.mImeToken,
377                     result.mImeWindowVis, result.mImeBackDisposition,
378                     result.mShowImeSwitcher);
379         }
380     }
381 
buildNavBarWindows()382     private void buildNavBarWindows() {
383         mTopSystemBarWindow = mCarSystemBarController.getTopWindow();
384         mBottomSystemBarWindow = mCarSystemBarController.getBottomWindow();
385         mLeftSystemBarWindow = mCarSystemBarController.getLeftWindow();
386         mRightSystemBarWindow = mCarSystemBarController.getRightWindow();
387     }
388 
buildNavBarContent()389     private void buildNavBarContent() {
390         mTopSystemBarView = mCarSystemBarController.getTopBar(isDeviceSetupForUser());
391         if (mTopSystemBarView != null) {
392             mSystemBarConfigs.insetSystemBar(SystemBarConfigs.TOP, mTopSystemBarView);
393             mHvacController.registerHvacViews(mTopSystemBarView);
394             mTopSystemBarWindow.addView(mTopSystemBarView);
395         }
396 
397         mBottomSystemBarView = mCarSystemBarController.getBottomBar(isDeviceSetupForUser());
398         if (mBottomSystemBarView != null) {
399             mSystemBarConfigs.insetSystemBar(SystemBarConfigs.BOTTOM, mBottomSystemBarView);
400             mHvacController.registerHvacViews(mBottomSystemBarView);
401             mBottomSystemBarWindow.addView(mBottomSystemBarView);
402         }
403 
404         mLeftSystemBarView = mCarSystemBarController.getLeftBar(isDeviceSetupForUser());
405         if (mLeftSystemBarView != null) {
406             mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, mLeftSystemBarView);
407             mHvacController.registerHvacViews(mLeftSystemBarView);
408             mLeftSystemBarWindow.addView(mLeftSystemBarView);
409         }
410 
411         mRightSystemBarView = mCarSystemBarController.getRightBar(isDeviceSetupForUser());
412         if (mRightSystemBarView != null) {
413             mSystemBarConfigs.insetSystemBar(SystemBarConfigs.RIGHT, mRightSystemBarView);
414             mHvacController.registerHvacViews(mRightSystemBarView);
415             mRightSystemBarWindow.addView(mRightSystemBarView);
416         }
417     }
418 
attachNavBarWindows()419     private void attachNavBarWindows() {
420         mSystemBarConfigs.getSystemBarSidesByZOrder().forEach(this::attachNavBarBySide);
421     }
422 
attachNavBarBySide(int side)423     private void attachNavBarBySide(int side) {
424         switch (side) {
425             case SystemBarConfigs.TOP:
426                 if (mTopSystemBarWindow != null) {
427                     mWindowManager.addView(mTopSystemBarWindow,
428                             mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.TOP));
429                 }
430                 break;
431             case SystemBarConfigs.BOTTOM:
432                 if (mBottomSystemBarWindow != null && !mBottomNavBarVisible) {
433                     mBottomNavBarVisible = true;
434 
435                     mWindowManager.addView(mBottomSystemBarWindow,
436                             mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.BOTTOM));
437                 }
438                 break;
439             case SystemBarConfigs.LEFT:
440                 if (mLeftSystemBarWindow != null) {
441                     mWindowManager.addView(mLeftSystemBarWindow,
442                             mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.LEFT));
443                 }
444                 break;
445             case SystemBarConfigs.RIGHT:
446                 if (mRightSystemBarWindow != null) {
447                     mWindowManager.addView(mRightSystemBarWindow,
448                             mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.RIGHT));
449                 }
450                 break;
451             default:
452                 return;
453         }
454     }
455 
456     /**
457      * We register for soft keyboard visibility events such that we can hide the navigation bar
458      * giving more screen space to the IME. Note: this is optional and controlled by
459      * {@code com.android.internal.R.bool.config_hideNavBarForKeyboard}.
460      */
461     @Override
setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher)462     public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
463             boolean showImeSwitcher) {
464         if (mContext.getDisplayId() != displayId) {
465             return;
466         }
467 
468         boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
469 
470         updateKeyboardVisibility(isKeyboardVisible);
471     }
472 
updateKeyboardVisibility(boolean isKeyboardVisible)473     private void updateKeyboardVisibility(boolean isKeyboardVisible) {
474         if (mHideTopBarForKeyboard) {
475             mCarSystemBarController.setTopWindowVisibility(
476                     isKeyboardVisible ? View.GONE : View.VISIBLE);
477         }
478 
479         if (mHideBottomBarForKeyboard) {
480             mCarSystemBarController.setBottomWindowVisibility(
481                     isKeyboardVisible ? View.GONE : View.VISIBLE);
482         }
483 
484         if (mHideLeftBarForKeyboard) {
485             mCarSystemBarController.setLeftWindowVisibility(
486                     isKeyboardVisible ? View.GONE : View.VISIBLE);
487         }
488         if (mHideRightBarForKeyboard) {
489             mCarSystemBarController.setRightWindowVisibility(
490                     isKeyboardVisible ? View.GONE : View.VISIBLE);
491         }
492     }
493 
494     @Override
onSystemBarAttributesChanged( int displayId, @WindowInsetsController.Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, @WindowInsetsController.Behavior int behavior, @InsetsType int requestedVisibleTypes, String packageName, LetterboxDetails[] letterboxDetails)495     public void onSystemBarAttributesChanged(
496             int displayId,
497             @WindowInsetsController.Appearance int appearance,
498             AppearanceRegion[] appearanceRegions,
499             boolean navbarColorManagedByIme,
500             @WindowInsetsController.Behavior int behavior,
501             @InsetsType int requestedVisibleTypes,
502             String packageName,
503             LetterboxDetails[] letterboxDetails) {
504         if (displayId != mDisplayId) {
505             return;
506         }
507         boolean barModeChanged = updateStatusBarMode(
508                 mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
509         int numStacks = appearanceRegions.length;
510         boolean stackAppearancesChanged = mAppearanceRegions.length != numStacks;
511         for (int i = 0; i < numStacks && !stackAppearancesChanged; i++) {
512             stackAppearancesChanged |= !appearanceRegions[i].equals(mAppearanceRegions[i]);
513         }
514         if (stackAppearancesChanged || barModeChanged) {
515             mAppearanceRegions = appearanceRegions;
516             updateStatusBarAppearance();
517         }
518         mCarSystemBarController.refreshSystemBar();
519     }
520 
521     @Override
disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2, boolean animate)522     public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2,
523             boolean animate) {
524         if (displayId != mDisplayId) {
525             return;
526         }
527         mCarSystemBarController.setSystemBarStates(state1, state2);
528     }
529 
updateStatusBarAppearance()530     private void updateStatusBarAppearance() {
531         int numStacks = mAppearanceRegions.length;
532         final ArrayList<Rect> lightBarBounds = new ArrayList<>();
533 
534         for (int i = 0; i < numStacks; i++) {
535             final AppearanceRegion ar = mAppearanceRegions[i];
536             if (isLight(ar.getAppearance())) {
537                 lightBarBounds.add(ar.getBounds());
538             }
539         }
540 
541         // If all stacks are light, all icons become dark.
542         if (lightBarBounds.size() == numStacks) {
543             mStatusBarIconController.setIconsDarkArea(null);
544             mStatusBarIconController.getTransitionsController().setIconsDark(
545                     /* dark= */ true, /* animate= */ false);
546         } else if (lightBarBounds.isEmpty()) {
547             // If no one is light, all icons become white.
548             mStatusBarIconController.getTransitionsController().setIconsDark(
549                     /* dark= */ false, /* animate= */ false);
550         } else {
551             // Not the same for every stack, update icons in area only.
552             mStatusBarIconController.setIconsDarkArea(lightBarBounds);
553             mStatusBarIconController.getTransitionsController().setIconsDark(
554                     /* dark= */ true, /* animate= */ false);
555         }
556     }
557 
isLight(int appearance)558     private static boolean isLight(int appearance) {
559         return (appearance & APPEARANCE_LIGHT_STATUS_BARS) != 0;
560     }
561 
562     @Override
showTransient(int displayId, int types)563     public void showTransient(int displayId, int types) {
564         if (displayId != mDisplayId) {
565             return;
566         }
567         if ((types & WindowInsets.Type.statusBars()) != 0) {
568             if (!mStatusBarTransientShown) {
569                 mStatusBarTransientShown = true;
570                 handleTransientChanged();
571             }
572         }
573         if ((types & WindowInsets.Type.navigationBars()) != 0) {
574             if (!mNavBarTransientShown) {
575                 mNavBarTransientShown = true;
576                 handleTransientChanged();
577             }
578         }
579     }
580 
581     @Override
abortTransient(int displayId, int types)582     public void abortTransient(int displayId, int types) {
583         if (displayId != mDisplayId) {
584             return;
585         }
586         if ((types & (WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars())) == 0) {
587             return;
588         }
589         clearTransient();
590     }
591 
clearTransient()592     private void clearTransient() {
593         if (mStatusBarTransientShown) {
594             mStatusBarTransientShown = false;
595             handleTransientChanged();
596         }
597         if (mNavBarTransientShown) {
598             mNavBarTransientShown = false;
599             handleTransientChanged();
600         }
601     }
602 
603     @VisibleForTesting
isStatusBarTransientShown()604     boolean isStatusBarTransientShown() {
605         return mStatusBarTransientShown;
606     }
607 
608     @VisibleForTesting
isNavBarTransientShown()609     boolean isNavBarTransientShown() {
610         return mNavBarTransientShown;
611     }
612 
613     @VisibleForTesting
setSignalPolicy(StatusBarSignalPolicy signalPolicy)614     void setSignalPolicy(StatusBarSignalPolicy signalPolicy) {
615         mSignalPolicy = signalPolicy;
616     }
617 
618     @Override
dump(PrintWriter pw, String[] args)619     public void dump(PrintWriter pw, String[] args) {
620         pw.print("  mTaskStackListener=");
621         pw.println(mButtonSelectionStateListener);
622         pw.print("  mBottomSystemBarView=");
623         pw.println(mBottomSystemBarView);
624     }
625 
handleTransientChanged()626     private void handleTransientChanged() {
627         updateStatusBarMode(mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
628         updateNavBarMode(mNavBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
629     }
630 
631     // Returns true if the status bar mode has changed.
updateStatusBarMode(int barMode)632     private boolean updateStatusBarMode(int barMode) {
633         if (mStatusBarMode != barMode) {
634             mStatusBarMode = barMode;
635             mAutoHideController.touchAutoHide();
636             return true;
637         }
638         return false;
639     }
640 
641     // Returns true if the nav bar mode has changed.
updateNavBarMode(int barMode)642     private boolean updateNavBarMode(int barMode) {
643         if (mSystemBarMode != barMode) {
644             mSystemBarMode = barMode;
645             mAutoHideController.touchAutoHide();
646             return true;
647         }
648         return false;
649     }
650 
651     @Override
onConfigChanged(Configuration newConfig)652     public void onConfigChanged(Configuration newConfig) {
653         boolean isConfigNightMode = newConfig.isNightModeActive();
654         // Only refresh UI on Night mode changes
655         if (isConfigNightMode != mIsUiModeNight) {
656             mIsUiModeNight = isConfigNightMode;
657             mUiModeManager.setNightModeActivated(mIsUiModeNight);
658 
659             // cache the current state
660             // The focused view will be destroyed during re-layout, causing the framework to adjust
661             // the focus unexpectedly. To avoid that, move focus to a view that won't be
662             // destroyed during re-layout and has no focus highlight (the FocusParkingView), then
663             // move focus back to the previously focused view after re-layout.
664             mCarSystemBarController.cacheAndHideFocus();
665             String selectedQuickControlsClsName = null;
666             View profilePickerView = null;
667             boolean isProfilePickerOpen = false;
668             if (mTopSystemBarView != null) {
669                 profilePickerView = mTopSystemBarView.findViewById(
670                         R.id.user_name);
671             }
672             if (profilePickerView != null) isProfilePickerOpen = profilePickerView.isSelected();
673             if (isProfilePickerOpen) {
674                 profilePickerView.callOnClick();
675             } else {
676                 selectedQuickControlsClsName =
677                         mCarSystemBarController.getSelectedQuickControlsClassName();
678                 mCarSystemBarController.callQuickControlsOnClickFromClassName(
679                         selectedQuickControlsClsName);
680             }
681 
682             mCarSystemBarController.resetCache();
683             restartNavBars();
684 
685             // retrieve the previous state
686             if (isProfilePickerOpen) {
687                 if (mTopSystemBarView != null) {
688                     profilePickerView = mTopSystemBarView.findViewById(
689                             R.id.user_name);
690                 }
691                 if (profilePickerView != null) profilePickerView.callOnClick();
692             } else {
693                 mCarSystemBarController.callQuickControlsOnClickFromClassName(
694                         selectedQuickControlsClsName);
695             }
696             mCarSystemBarController.restoreFocus();
697         }
698     }
699 
700     @VisibleForTesting
setUiModeManager(UiModeManager uiModeManager)701     void setUiModeManager(UiModeManager uiModeManager) {
702         mUiModeManager = uiModeManager;
703     }
704 
705     @Override
onKeyboardVisibilityChanged(boolean show)706     public void onKeyboardVisibilityChanged(boolean show) {
707         updateKeyboardVisibility(show);
708     }
709 }
710