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.navigationbar;
18 
19 import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
20 import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
21 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
22 import static android.view.InsetsState.ITYPE_STATUS_BAR;
23 import static android.view.InsetsState.containsType;
24 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
25 
26 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
27 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
28 
29 import android.content.Context;
30 import android.content.res.Resources;
31 import android.graphics.PixelFormat;
32 import android.inputmethodservice.InputMethodService;
33 import android.os.Handler;
34 import android.os.IBinder;
35 import android.os.RemoteException;
36 import android.view.Display;
37 import android.view.Gravity;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.view.WindowInsetsController;
41 import android.view.WindowManager;
42 
43 import androidx.annotation.VisibleForTesting;
44 
45 import com.android.internal.statusbar.IStatusBarService;
46 import com.android.internal.statusbar.RegisterStatusBarResult;
47 import com.android.internal.view.AppearanceRegion;
48 import com.android.systemui.R;
49 import com.android.systemui.SystemUI;
50 import com.android.systemui.car.CarDeviceProvisionedController;
51 import com.android.systemui.car.CarDeviceProvisionedListener;
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.shared.system.ActivityManagerWrapper;
56 import com.android.systemui.statusbar.AutoHideUiElement;
57 import com.android.systemui.statusbar.CommandQueue;
58 import com.android.systemui.statusbar.phone.AutoHideController;
59 import com.android.systemui.statusbar.phone.BarTransitions;
60 import com.android.systemui.statusbar.phone.LightBarController;
61 import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
62 import com.android.systemui.statusbar.phone.StatusBarIconController;
63 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
64 import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher;
65 import com.android.systemui.statusbar.policy.KeyguardStateController;
66 
67 import java.io.FileDescriptor;
68 import java.io.PrintWriter;
69 import java.util.concurrent.Executor;
70 
71 import javax.inject.Inject;
72 
73 import dagger.Lazy;
74 
75 /** Navigation bars customized for the automotive use case. */
76 public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks {
77 
78     private final Resources mResources;
79     private final CarNavigationBarController mCarNavigationBarController;
80     private final SysuiDarkIconDispatcher mStatusBarIconController;
81     private final WindowManager mWindowManager;
82     private final CarDeviceProvisionedController mCarDeviceProvisionedController;
83     private final CommandQueue mCommandQueue;
84     private final AutoHideController mAutoHideController;
85     private final ButtonSelectionStateListener mButtonSelectionStateListener;
86     private final Handler mMainHandler;
87     private final Executor mUiBgExecutor;
88     private final IStatusBarService mBarService;
89     private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy;
90     private final Lazy<PhoneStatusBarPolicy> mIconPolicyLazy;
91     private final Lazy<StatusBarIconController> mIconControllerLazy;
92 
93     private final int mDisplayId;
94 
95     private StatusBarSignalPolicy mSignalPolicy;
96     private ActivityManagerWrapper mActivityManagerWrapper;
97 
98     // If the nav bar should be hidden when the soft keyboard is visible.
99     private boolean mHideNavBarForKeyboard;
100     private boolean mBottomNavBarVisible;
101 
102     // Nav bar views.
103     private ViewGroup mTopNavigationBarWindow;
104     private ViewGroup mBottomNavigationBarWindow;
105     private ViewGroup mLeftNavigationBarWindow;
106     private ViewGroup mRightNavigationBarWindow;
107     private CarNavigationBarView mTopNavigationBarView;
108     private CarNavigationBarView mBottomNavigationBarView;
109     private CarNavigationBarView mLeftNavigationBarView;
110     private CarNavigationBarView mRightNavigationBarView;
111 
112     // To be attached to the navigation bars such that they can close the notification panel if
113     // it's open.
114     private boolean mDeviceIsSetUpForUser = true;
115     private boolean mIsUserSetupInProgress = false;
116 
117     private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
118     @BarTransitions.TransitionMode
119     private int mStatusBarMode;
120     @BarTransitions.TransitionMode
121     private int mNavigationBarMode;
122     private boolean mStatusBarTransientShown;
123     private boolean mNavBarTransientShown;
124 
125     @Inject
CarNavigationBar(Context context, @Main Resources resources, CarNavigationBarController carNavigationBarController, LightBarController lightBarController, DarkIconDispatcher darkIconDispatcher, WindowManager windowManager, CarDeviceProvisionedController deviceProvisionedController, CommandQueue commandQueue, AutoHideController autoHideController, ButtonSelectionStateListener buttonSelectionStateListener, @Main Handler mainHandler, @UiBackground Executor uiBgExecutor, IStatusBarService barService, Lazy<KeyguardStateController> keyguardStateControllerLazy, Lazy<PhoneStatusBarPolicy> iconPolicyLazy, Lazy<StatusBarIconController> iconControllerLazy )126     public CarNavigationBar(Context context,
127             @Main Resources resources,
128             CarNavigationBarController carNavigationBarController,
129             // TODO(b/156052638): Should not need to inject LightBarController
130             LightBarController lightBarController,
131             DarkIconDispatcher darkIconDispatcher,
132             WindowManager windowManager,
133             CarDeviceProvisionedController deviceProvisionedController,
134             CommandQueue commandQueue,
135             AutoHideController autoHideController,
136             ButtonSelectionStateListener buttonSelectionStateListener,
137             @Main Handler mainHandler,
138             @UiBackground Executor uiBgExecutor,
139             IStatusBarService barService,
140             Lazy<KeyguardStateController> keyguardStateControllerLazy,
141             Lazy<PhoneStatusBarPolicy> iconPolicyLazy,
142             Lazy<StatusBarIconController> iconControllerLazy
143     ) {
144         super(context);
145         mResources = resources;
146         mCarNavigationBarController = carNavigationBarController;
147         mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
148         mWindowManager = windowManager;
149         mCarDeviceProvisionedController = deviceProvisionedController;
150         mCommandQueue = commandQueue;
151         mAutoHideController = autoHideController;
152         mButtonSelectionStateListener = buttonSelectionStateListener;
153         mMainHandler = mainHandler;
154         mUiBgExecutor = uiBgExecutor;
155         mBarService = barService;
156         mKeyguardStateControllerLazy = keyguardStateControllerLazy;
157         mIconPolicyLazy = iconPolicyLazy;
158         mIconControllerLazy = iconControllerLazy;
159 
160         mDisplayId = context.getDisplayId();
161     }
162 
163     @Override
start()164     public void start() {
165         // Set initial state.
166         mHideNavBarForKeyboard = mResources.getBoolean(
167                 com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
168         mBottomNavBarVisible = false;
169 
170         // Connect into the status bar manager service
171         mCommandQueue.addCallback(this);
172 
173         RegisterStatusBarResult result = null;
174         try {
175             result = mBarService.registerStatusBar(mCommandQueue);
176         } catch (RemoteException ex) {
177             ex.rethrowFromSystemServer();
178         }
179 
180         onSystemBarAppearanceChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
181                 result.mNavbarColorManagedByIme);
182 
183         // StatusBarManagerService has a back up of IME token and it's restored here.
184         setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
185                 result.mImeBackDisposition, result.mShowImeSwitcher);
186 
187         // Set up the initial icon state
188         int numIcons = result.mIcons.size();
189         for (int i = 0; i < numIcons; i++) {
190             mCommandQueue.setIcon(result.mIcons.keyAt(i), result.mIcons.valueAt(i));
191         }
192 
193         mAutoHideController.setStatusBar(new AutoHideUiElement() {
194             @Override
195             public void synchronizeState() {
196                 // No op.
197             }
198 
199             @Override
200             public boolean isVisible() {
201                 return mStatusBarTransientShown;
202             }
203 
204             @Override
205             public void hide() {
206                 clearTransient();
207             }
208         });
209 
210         mAutoHideController.setNavigationBar(new AutoHideUiElement() {
211             @Override
212             public void synchronizeState() {
213                 // No op.
214             }
215 
216             @Override
217             public boolean isVisible() {
218                 return mNavBarTransientShown;
219             }
220 
221             @Override
222             public void hide() {
223                 clearTransient();
224             }
225         });
226 
227         mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup();
228         mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress();
229         mCarDeviceProvisionedController.addCallback(
230                 new CarDeviceProvisionedListener() {
231                     @Override
232                     public void onUserSetupInProgressChanged() {
233                         mMainHandler.post(() -> restartNavBarsIfNecessary());
234                     }
235 
236                     @Override
237                     public void onUserSetupChanged() {
238                         mMainHandler.post(() -> restartNavBarsIfNecessary());
239                     }
240 
241                     @Override
242                     public void onUserSwitched() {
243                         mMainHandler.post(() -> restartNavBarsIfNecessary());
244                     }
245                 });
246 
247         createNavigationBar(result);
248 
249         mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
250         mActivityManagerWrapper.registerTaskStackListener(mButtonSelectionStateListener);
251 
252         mUiBgExecutor.execute(mCarNavigationBarController::connectToHvac);
253 
254         // Lastly, call to the icon policy to install/update all the icons.
255         // Must be called on the main thread due to the use of observeForever() in
256         // mIconPolicy.init().
257         mMainHandler.post(() -> {
258             mIconPolicyLazy.get().init();
259             mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconControllerLazy.get());
260         });
261     }
262 
restartNavBarsIfNecessary()263     private void restartNavBarsIfNecessary() {
264         boolean currentUserSetup = mCarDeviceProvisionedController.isCurrentUserSetup();
265         boolean currentUserSetupInProgress = mCarDeviceProvisionedController
266                 .isCurrentUserSetupInProgress();
267         if (mIsUserSetupInProgress != currentUserSetupInProgress
268                 || mDeviceIsSetUpForUser != currentUserSetup) {
269             mDeviceIsSetUpForUser = currentUserSetup;
270             mIsUserSetupInProgress = currentUserSetupInProgress;
271             restartNavBars();
272         }
273     }
274 
275     /**
276      * Remove all content from navbars and rebuild them. Used to allow for different nav bars
277      * before and after the device is provisioned. . Also for change of density and font size.
278      */
restartNavBars()279     private void restartNavBars() {
280         // remove and reattach all components such that we don't keep a reference to unused ui
281         // elements
282         mCarNavigationBarController.removeAll();
283 
284         if (mTopNavigationBarWindow != null) {
285             mTopNavigationBarWindow.removeAllViews();
286             mTopNavigationBarView = null;
287         }
288 
289         if (mBottomNavigationBarWindow != null) {
290             mBottomNavigationBarWindow.removeAllViews();
291             mBottomNavigationBarView = null;
292         }
293 
294         if (mLeftNavigationBarWindow != null) {
295             mLeftNavigationBarWindow.removeAllViews();
296             mLeftNavigationBarView = null;
297         }
298 
299         if (mRightNavigationBarWindow != null) {
300             mRightNavigationBarWindow.removeAllViews();
301             mRightNavigationBarView = null;
302         }
303 
304         buildNavBarContent();
305         // If the UI was rebuilt (day/night change or user change) while the keyguard was up we need
306         // to correctly respect that state.
307         if (mKeyguardStateControllerLazy.get().isShowing()) {
308             mCarNavigationBarController.showAllKeyguardButtons(isDeviceSetupForUser());
309         } else {
310             mCarNavigationBarController.hideAllKeyguardButtons(isDeviceSetupForUser());
311         }
312 
313         // Upon restarting the Navigation Bar, CarFacetButtonController should immediately apply the
314         // selection state that reflects the current task stack.
315         mButtonSelectionStateListener.onTaskStackChanged();
316     }
317 
isDeviceSetupForUser()318     private boolean isDeviceSetupForUser() {
319         return mDeviceIsSetUpForUser && !mIsUserSetupInProgress;
320     }
321 
createNavigationBar(RegisterStatusBarResult result)322     private void createNavigationBar(RegisterStatusBarResult result) {
323         buildNavBarWindows();
324         buildNavBarContent();
325         attachNavBarWindows();
326 
327         // Try setting up the initial state of the nav bar if applicable.
328         if (result != null) {
329             setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken,
330                     result.mImeWindowVis, result.mImeBackDisposition,
331                     result.mShowImeSwitcher);
332         }
333     }
334 
buildNavBarWindows()335     private void buildNavBarWindows() {
336         mTopNavigationBarWindow = mCarNavigationBarController.getTopWindow();
337         mBottomNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
338         mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow();
339         mRightNavigationBarWindow = mCarNavigationBarController.getRightWindow();
340     }
341 
buildNavBarContent()342     private void buildNavBarContent() {
343         mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
344         if (mTopNavigationBarView != null) {
345             mTopNavigationBarWindow.addView(mTopNavigationBarView);
346         }
347 
348         mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
349         if (mBottomNavigationBarView != null) {
350             mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
351         }
352 
353         mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
354         if (mLeftNavigationBarView != null) {
355             mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
356         }
357 
358         mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
359         if (mRightNavigationBarView != null) {
360             mRightNavigationBarWindow.addView(mRightNavigationBarView);
361         }
362     }
363 
attachNavBarWindows()364     private void attachNavBarWindows() {
365         if (mTopNavigationBarWindow != null) {
366             int height = mResources.getDimensionPixelSize(
367                     com.android.internal.R.dimen.status_bar_height);
368             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
369                     ViewGroup.LayoutParams.MATCH_PARENT,
370                     height,
371                     WindowManager.LayoutParams.TYPE_STATUS_BAR,
372                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
373                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
374                             | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
375                             | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
376                     PixelFormat.TRANSLUCENT);
377             lp.setTitle("TopCarNavigationBar");
378             lp.windowAnimations = 0;
379             lp.gravity = Gravity.TOP;
380             mWindowManager.addView(mTopNavigationBarWindow, lp);
381         }
382 
383         if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
384             mBottomNavBarVisible = true;
385             int height = mResources.getDimensionPixelSize(
386                     com.android.internal.R.dimen.navigation_bar_height);
387 
388             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
389                     ViewGroup.LayoutParams.MATCH_PARENT,
390                     height,
391                     WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
392                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
393                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
394                             | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
395                             | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
396                     PixelFormat.TRANSLUCENT);
397             lp.setTitle("BottomCarNavigationBar");
398             lp.windowAnimations = 0;
399             lp.gravity = Gravity.BOTTOM;
400             mWindowManager.addView(mBottomNavigationBarWindow, lp);
401         }
402 
403         if (mLeftNavigationBarWindow != null) {
404             int width = mResources.getDimensionPixelSize(
405                     R.dimen.car_left_navigation_bar_width);
406             WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
407                     width, ViewGroup.LayoutParams.MATCH_PARENT,
408                     WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
409                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
410                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
411                             | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
412                             | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
413                     PixelFormat.TRANSLUCENT);
414             leftlp.setTitle("LeftCarNavigationBar");
415             leftlp.providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
416             leftlp.setFitInsetsTypes(0);
417             leftlp.windowAnimations = 0;
418             leftlp.gravity = Gravity.LEFT;
419             mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
420         }
421 
422         if (mRightNavigationBarWindow != null) {
423             int width = mResources.getDimensionPixelSize(
424                     R.dimen.car_right_navigation_bar_width);
425             WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
426                     width, ViewGroup.LayoutParams.MATCH_PARENT,
427                     WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
428                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
429                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
430                             | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
431                             | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
432                     PixelFormat.TRANSLUCENT);
433             rightlp.setTitle("RightCarNavigationBar");
434             rightlp.providesInsetsTypes = new int[]{ITYPE_EXTRA_NAVIGATION_BAR};
435             rightlp.setFitInsetsTypes(0);
436             rightlp.windowAnimations = 0;
437             rightlp.gravity = Gravity.RIGHT;
438             mWindowManager.addView(mRightNavigationBarWindow, rightlp);
439         }
440     }
441 
442     /**
443      * We register for soft keyboard visibility events such that we can hide the navigation bar
444      * giving more screen space to the IME. Note: this is optional and controlled by
445      * {@code com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard}.
446      */
447     @Override
setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher)448     public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
449             boolean showImeSwitcher) {
450         if (!mHideNavBarForKeyboard) {
451             return;
452         }
453 
454         if (mContext.getDisplayId() != displayId) {
455             return;
456         }
457 
458         boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
459         mCarNavigationBarController.setBottomWindowVisibility(
460                 isKeyboardVisible ? View.GONE : View.VISIBLE);
461     }
462 
463     @Override
onSystemBarAppearanceChanged( int displayId, @WindowInsetsController.Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme)464     public void onSystemBarAppearanceChanged(
465             int displayId,
466             @WindowInsetsController.Appearance int appearance,
467             AppearanceRegion[] appearanceRegions,
468             boolean navbarColorManagedByIme) {
469         if (displayId != mDisplayId) {
470             return;
471         }
472         boolean barModeChanged = updateStatusBarMode(
473                 mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
474         int numStacks = appearanceRegions.length;
475         boolean stackAppearancesChanged = mAppearanceRegions.length != numStacks;
476         for (int i = 0; i < numStacks && !stackAppearancesChanged; i++) {
477             stackAppearancesChanged |= !appearanceRegions[i].equals(mAppearanceRegions[i]);
478         }
479         if (stackAppearancesChanged || barModeChanged) {
480             mAppearanceRegions = appearanceRegions;
481             updateStatusBarAppearance();
482         }
483     }
484 
updateStatusBarAppearance()485     private void updateStatusBarAppearance() {
486         int numStacks = mAppearanceRegions.length;
487         int numLightStacks = 0;
488 
489         // We can only have maximum one light stack.
490         int indexLightStack = -1;
491 
492         for (int i = 0; i < numStacks; i++) {
493             if (isLight(mAppearanceRegions[i].getAppearance())) {
494                 numLightStacks++;
495                 indexLightStack = i;
496             }
497         }
498 
499         // If all stacks are light, all icons become dark.
500         if (numLightStacks == numStacks) {
501             mStatusBarIconController.setIconsDarkArea(null);
502             mStatusBarIconController.getTransitionsController().setIconsDark(
503                     /* dark= */ true, /* animate= */ false);
504         } else if (numLightStacks == 0) {
505             // If no one is light, all icons become white.
506             mStatusBarIconController.getTransitionsController().setIconsDark(
507                     /* dark= */ false, /* animate= */ false);
508         } else {
509             // Not the same for every stack, update icons in area only.
510             mStatusBarIconController.setIconsDarkArea(
511                     mAppearanceRegions[indexLightStack].getBounds());
512             mStatusBarIconController.getTransitionsController().setIconsDark(
513                     /* dark= */ true, /* animate= */ false);
514         }
515     }
516 
isLight(int appearance)517     private static boolean isLight(int appearance) {
518         return (appearance & APPEARANCE_LIGHT_STATUS_BARS) != 0;
519     }
520 
521     @Override
showTransient(int displayId, int[] types)522     public void showTransient(int displayId, int[] types) {
523         if (displayId != mDisplayId) {
524             return;
525         }
526         if (containsType(types, ITYPE_STATUS_BAR)) {
527             if (!mStatusBarTransientShown) {
528                 mStatusBarTransientShown = true;
529                 handleTransientChanged();
530             }
531         }
532         if (containsType(types, ITYPE_NAVIGATION_BAR)) {
533             if (!mNavBarTransientShown) {
534                 mNavBarTransientShown = true;
535                 handleTransientChanged();
536             }
537         }
538     }
539 
540     @Override
abortTransient(int displayId, int[] types)541     public void abortTransient(int displayId, int[] types) {
542         if (displayId != mDisplayId) {
543             return;
544         }
545         if (!containsType(types, ITYPE_STATUS_BAR) && !containsType(types, ITYPE_NAVIGATION_BAR)) {
546             return;
547         }
548         clearTransient();
549     }
550 
clearTransient()551     private void clearTransient() {
552         if (mStatusBarTransientShown) {
553             mStatusBarTransientShown = false;
554             handleTransientChanged();
555         }
556         if (mNavBarTransientShown) {
557             mNavBarTransientShown = false;
558             handleTransientChanged();
559         }
560     }
561 
562     @VisibleForTesting
isStatusBarTransientShown()563     boolean isStatusBarTransientShown() {
564         return mStatusBarTransientShown;
565     }
566 
567     @VisibleForTesting
isNavBarTransientShown()568     boolean isNavBarTransientShown() {
569         return mNavBarTransientShown;
570     }
571 
572     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)573     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
574         pw.print("  mTaskStackListener=");
575         pw.println(mButtonSelectionStateListener);
576         pw.print("  mBottomNavigationBarView=");
577         pw.println(mBottomNavigationBarView);
578     }
579 
handleTransientChanged()580     private void handleTransientChanged() {
581         updateStatusBarMode(mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
582         updateNavBarMode(mNavBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
583     }
584 
585     // Returns true if the status bar mode has changed.
updateStatusBarMode(int barMode)586     private boolean updateStatusBarMode(int barMode) {
587         if (mStatusBarMode != barMode) {
588             mStatusBarMode = barMode;
589             mAutoHideController.touchAutoHide();
590             return true;
591         }
592         return false;
593     }
594 
595     // Returns true if the nav bar mode has changed.
updateNavBarMode(int barMode)596     private boolean updateNavBarMode(int barMode) {
597         if (mNavigationBarMode != barMode) {
598             mNavigationBarMode = barMode;
599             mAutoHideController.touchAutoHide();
600             return true;
601         }
602         return false;
603     }
604 }
605