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 android.app.ActivityManager;
20 import android.app.StatusBarManager;
21 import android.content.Context;
22 import android.os.Build;
23 import android.util.Log;
24 import android.view.Gravity;
25 import android.view.View;
26 import android.view.ViewGroup;
27 import android.widget.Toast;
28 
29 import androidx.annotation.Nullable;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.systemui.R;
33 import com.android.systemui.broadcast.BroadcastDispatcher;
34 import com.android.systemui.car.CarServiceProvider;
35 import com.android.systemui.car.hvac.HvacPanelOverlayViewController;
36 import com.android.systemui.car.privacy.MicQcPanel;
37 import com.android.systemui.car.statusbar.UserNameViewController;
38 import com.android.systemui.car.statusicon.StatusIconPanelController;
39 import com.android.systemui.dagger.SysUISingleton;
40 import com.android.systemui.statusbar.policy.ConfigurationController;
41 
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 import javax.inject.Inject;
46 
47 import dagger.Lazy;
48 
49 /** A single class which controls the navigation bar views. */
50 @SysUISingleton
51 public class CarSystemBarController {
52     private static final boolean DEBUG = Build.IS_ENG || Build.IS_USERDEBUG;
53 
54     private static final String TAG = CarSystemBarController.class.getSimpleName();
55 
56     private final Context mContext;
57     private final CarSystemBarViewFactory mCarSystemBarViewFactory;
58     private final CarServiceProvider mCarServiceProvider;
59     private final BroadcastDispatcher mBroadcastDispatcher;
60     private final ConfigurationController mConfigurationController;
61     private final ButtonSelectionStateController mButtonSelectionStateController;
62     private final ButtonRoleHolderController mButtonRoleHolderController;
63     private final Lazy<UserNameViewController> mUserNameViewControllerLazy;
64     private final Lazy<PrivacyChipViewController> mPrivacyChipViewControllerLazy;
65     private final Lazy<MicQcPanel.MicPrivacyElementsProvider> mMicPrivacyElementsProviderLazy;
66 
67     private final boolean mShowTop;
68     private final boolean mShowBottom;
69     private final boolean mShowLeft;
70     private final boolean mShowRight;
71     private final int mPrivacyChipXOffset;
72 
73     private View.OnTouchListener mTopBarTouchListener;
74     private View.OnTouchListener mBottomBarTouchListener;
75     private View.OnTouchListener mLeftBarTouchListener;
76     private View.OnTouchListener mRightBarTouchListener;
77     private NotificationsShadeController mNotificationsShadeController;
78     private HvacPanelController mHvacPanelController;
79     private StatusIconPanelController mMicPanelController;
80     private StatusIconPanelController mProfilePanelController;
81     private HvacPanelOverlayViewController mHvacPanelOverlayViewController;
82 
83     private CarSystemBarView mTopView;
84     private CarSystemBarView mBottomView;
85     private CarSystemBarView mLeftView;
86     private CarSystemBarView mRightView;
87 
88     private int mStatusBarState;
89 
90     @Inject
CarSystemBarController(Context context, CarSystemBarViewFactory carSystemBarViewFactory, CarServiceProvider carServiceProvider, BroadcastDispatcher broadcastDispatcher, ConfigurationController configurationController, ButtonSelectionStateController buttonSelectionStateController, Lazy<UserNameViewController> userNameViewControllerLazy, Lazy<PrivacyChipViewController> privacyChipViewControllerLazy, ButtonRoleHolderController buttonRoleHolderController, SystemBarConfigs systemBarConfigs, Lazy<MicQcPanel.MicPrivacyElementsProvider> micPrivacyElementsProvider)91     public CarSystemBarController(Context context,
92             CarSystemBarViewFactory carSystemBarViewFactory,
93             CarServiceProvider carServiceProvider,
94             BroadcastDispatcher broadcastDispatcher,
95             ConfigurationController configurationController,
96             ButtonSelectionStateController buttonSelectionStateController,
97             Lazy<UserNameViewController> userNameViewControllerLazy,
98             Lazy<PrivacyChipViewController> privacyChipViewControllerLazy,
99             ButtonRoleHolderController buttonRoleHolderController,
100             SystemBarConfigs systemBarConfigs,
101             Lazy<MicQcPanel.MicPrivacyElementsProvider> micPrivacyElementsProvider) {
102         mContext = context;
103         mCarSystemBarViewFactory = carSystemBarViewFactory;
104         mCarServiceProvider = carServiceProvider;
105         mBroadcastDispatcher = broadcastDispatcher;
106         mConfigurationController = configurationController;
107         mButtonSelectionStateController = buttonSelectionStateController;
108         mUserNameViewControllerLazy = userNameViewControllerLazy;
109         mPrivacyChipViewControllerLazy = privacyChipViewControllerLazy;
110         mButtonRoleHolderController = buttonRoleHolderController;
111         mMicPrivacyElementsProviderLazy = micPrivacyElementsProvider;
112 
113         // Read configuration.
114         mShowTop = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.TOP);
115         mShowBottom = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.BOTTOM);
116         mShowLeft = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.LEFT);
117         mShowRight = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.RIGHT);
118 
119         mPrivacyChipXOffset = -context.getResources()
120                 .getDimensionPixelOffset(R.dimen.privacy_chip_horizontal_padding);
121     }
122 
123     /**
124      * Hides all system bars.
125      */
hideBars()126     public void hideBars() {
127         setTopWindowVisibility(View.GONE);
128         setBottomWindowVisibility(View.GONE);
129         setLeftWindowVisibility(View.GONE);
130         setRightWindowVisibility(View.GONE);
131     }
132 
133     /**
134      * Shows all system bars.
135      */
showBars()136     public void showBars() {
137         setTopWindowVisibility(View.VISIBLE);
138         setBottomWindowVisibility(View.VISIBLE);
139         setLeftWindowVisibility(View.VISIBLE);
140         setRightWindowVisibility(View.VISIBLE);
141     }
142 
143     /** Clean up */
removeAll()144     public void removeAll() {
145         mButtonSelectionStateController.removeAll();
146         mButtonRoleHolderController.removeAll();
147         mUserNameViewControllerLazy.get().removeAll();
148         mPrivacyChipViewControllerLazy.get().removeAll();
149         mMicPanelController = null;
150         mProfilePanelController = null;
151     }
152 
153     /** Gets the top window if configured to do so. */
154     @Nullable
getTopWindow()155     public ViewGroup getTopWindow() {
156         return mShowTop ? mCarSystemBarViewFactory.getTopWindow() : null;
157     }
158 
159     /** Gets the bottom window if configured to do so. */
160     @Nullable
getBottomWindow()161     public ViewGroup getBottomWindow() {
162         return mShowBottom ? mCarSystemBarViewFactory.getBottomWindow() : null;
163     }
164 
165     /** Gets the left window if configured to do so. */
166     @Nullable
getLeftWindow()167     public ViewGroup getLeftWindow() {
168         return mShowLeft ? mCarSystemBarViewFactory.getLeftWindow() : null;
169     }
170 
171     /** Gets the right window if configured to do so. */
172     @Nullable
getRightWindow()173     public ViewGroup getRightWindow() {
174         return mShowRight ? mCarSystemBarViewFactory.getRightWindow() : null;
175     }
176 
177     /** Toggles the top nav bar visibility. */
setTopWindowVisibility(@iew.Visibility int visibility)178     public boolean setTopWindowVisibility(@View.Visibility int visibility) {
179         return setWindowVisibility(getTopWindow(), visibility);
180     }
181 
182     /** Toggles the bottom nav bar visibility. */
setBottomWindowVisibility(@iew.Visibility int visibility)183     public boolean setBottomWindowVisibility(@View.Visibility int visibility) {
184         return setWindowVisibility(getBottomWindow(), visibility);
185     }
186 
187     /** Toggles the left nav bar visibility. */
setLeftWindowVisibility(@iew.Visibility int visibility)188     public boolean setLeftWindowVisibility(@View.Visibility int visibility) {
189         return setWindowVisibility(getLeftWindow(), visibility);
190     }
191 
192     /** Toggles the right nav bar visibility. */
setRightWindowVisibility(@iew.Visibility int visibility)193     public boolean setRightWindowVisibility(@View.Visibility int visibility) {
194         return setWindowVisibility(getRightWindow(), visibility);
195     }
196 
setWindowVisibility(ViewGroup window, @View.Visibility int visibility)197     private boolean setWindowVisibility(ViewGroup window, @View.Visibility int visibility) {
198         if (window == null) {
199             return false;
200         }
201 
202         if (window.getVisibility() == visibility) {
203             return false;
204         }
205 
206         window.setVisibility(visibility);
207         return true;
208     }
209 
210     /**
211      * Sets the status bar state and refreshes the system bar when the state was changed.
212      */
setStatusBarState(int state)213     public void setStatusBarState(int state) {
214         int diff = state ^ mStatusBarState;
215         if (diff == 0) {
216             if (DEBUG) {
217                 Log.d(TAG, "setStatusBarState(): status bar states unchanged: "
218                         + state);
219             }
220             return;
221         }
222         mStatusBarState = state;
223         refreshSystemBarByLockTaskFeatures();
224     }
225 
226     @VisibleForTesting
getStatusBarState()227     protected int getStatusBarState() {
228         return mStatusBarState;
229     }
230 
231     /**
232      * Refreshes certain system bar views when lock task mode feature is changed based on
233      * {@link StatusBarManager} flags.
234      */
refreshSystemBarByLockTaskFeatures()235     public void refreshSystemBarByLockTaskFeatures() {
236         boolean locked = isLockTaskModeLocked();
237         int lockTaskModeVisibility = locked ? View.GONE : View.VISIBLE;
238         boolean homeDisabled = ((mStatusBarState & StatusBarManager.DISABLE_HOME) > 0);
239         boolean notificationDisabled =
240                 ((mStatusBarState & StatusBarManager.DISABLE_NOTIFICATION_ICONS) > 0);
241         if (DEBUG) {
242             Log.d(TAG, "refreshSystemBarByLockTaskFeatures: locked?: " + locked
243                     + " homeDisabled: " + homeDisabled
244                     + " notificationDisabled: " + notificationDisabled);
245         }
246 
247         setLockTaskDisabledContainer(R.id.qc_entry_points_container, lockTaskModeVisibility);
248         setLockTaskDisabledContainer(R.id.user_name_container, lockTaskModeVisibility);
249 
250         // Check navigation icons
251         setLockTaskDisabledButton(R.id.home, homeDisabled);
252         setLockTaskDisabledButton(R.id.phone_nav, locked);
253         setLockTaskDisabledButton(R.id.grid_nav, homeDisabled);
254         setLockTaskDisabledButton(R.id.notifications, notificationDisabled);
255     }
256 
isLockTaskModeLocked()257     private boolean isLockTaskModeLocked() {
258         return mContext.getSystemService(ActivityManager.class).getLockTaskModeState()
259                 == ActivityManager.LOCK_TASK_MODE_LOCKED;
260     }
261 
setLockTaskDisabledButton(int viewId, boolean disabled)262     private void setLockTaskDisabledButton(int viewId, boolean disabled) {
263         for (CarSystemBarView barView : getAllAvailableSystemBarViews()) {
264             barView.setLockTaskDisabledButton(viewId, disabled, () ->
265                     showAdminSupportDetailsDialog());
266         }
267     }
268 
setLockTaskDisabledContainer(int viewId, @View.Visibility int visibility)269     private void setLockTaskDisabledContainer(int viewId, @View.Visibility int visibility) {
270         for (CarSystemBarView barView : getAllAvailableSystemBarViews()) {
271             barView.setLockTaskDisabledContainer(viewId, visibility);
272         }
273     }
274 
showAdminSupportDetailsDialog()275     private void showAdminSupportDetailsDialog() {
276         // TODO(b/205891123): launch AdminSupportDetailsDialog after moving
277         // AdminSupportDetailsDialog out of CarSettings since CarSettings is not and should not
278         // be allowlisted for lock task mode.
279         Toast.makeText(mContext, "This action is unavailable for your profile",
280                 Toast.LENGTH_LONG).show();
281     }
282 
283     /** Gets the top navigation bar with the appropriate listeners set. */
284     @Nullable
getTopBar(boolean isSetUp)285     public CarSystemBarView getTopBar(boolean isSetUp) {
286         if (!mShowTop) {
287             return null;
288         }
289 
290         mTopView = mCarSystemBarViewFactory.getTopBar(isSetUp);
291         setupBar(mTopView, mTopBarTouchListener, mNotificationsShadeController,
292                 mHvacPanelController, mHvacPanelOverlayViewController);
293 
294         if (isSetUp) {
295             // We do not want the mic privacy chip or the profile picker to be clickable in
296             // unprovisioned mode.
297             setupMicQcPanel();
298             setupProfilePanel();
299         }
300 
301         return mTopView;
302     }
303 
304     /** Gets the bottom navigation bar with the appropriate listeners set. */
305     @Nullable
getBottomBar(boolean isSetUp)306     public CarSystemBarView getBottomBar(boolean isSetUp) {
307         if (!mShowBottom) {
308             return null;
309         }
310 
311         mBottomView = mCarSystemBarViewFactory.getBottomBar(isSetUp);
312         setupBar(mBottomView, mBottomBarTouchListener, mNotificationsShadeController,
313                 mHvacPanelController, mHvacPanelOverlayViewController);
314         return mBottomView;
315     }
316 
317     /** Gets the left navigation bar with the appropriate listeners set. */
318     @Nullable
getLeftBar(boolean isSetUp)319     public CarSystemBarView getLeftBar(boolean isSetUp) {
320         if (!mShowLeft) {
321             return null;
322         }
323 
324         mLeftView = mCarSystemBarViewFactory.getLeftBar(isSetUp);
325         setupBar(mLeftView, mLeftBarTouchListener, mNotificationsShadeController,
326                 mHvacPanelController, mHvacPanelOverlayViewController);
327         return mLeftView;
328     }
329 
330     /** Gets the right navigation bar with the appropriate listeners set. */
331     @Nullable
getRightBar(boolean isSetUp)332     public CarSystemBarView getRightBar(boolean isSetUp) {
333         if (!mShowRight) {
334             return null;
335         }
336 
337         mRightView = mCarSystemBarViewFactory.getRightBar(isSetUp);
338         setupBar(mRightView, mRightBarTouchListener, mNotificationsShadeController,
339                 mHvacPanelController, mHvacPanelOverlayViewController);
340         return mRightView;
341     }
342 
setupBar(CarSystemBarView view, View.OnTouchListener statusBarTouchListener, NotificationsShadeController notifShadeController, HvacPanelController hvacPanelController, HvacPanelOverlayViewController hvacPanelOverlayViewController)343     private void setupBar(CarSystemBarView view, View.OnTouchListener statusBarTouchListener,
344             NotificationsShadeController notifShadeController,
345             HvacPanelController hvacPanelController,
346             HvacPanelOverlayViewController hvacPanelOverlayViewController) {
347         view.setStatusBarWindowTouchListener(statusBarTouchListener);
348         view.setNotificationsPanelController(notifShadeController);
349         view.setHvacPanelController(hvacPanelController);
350         view.registerHvacPanelOverlayViewController(hvacPanelOverlayViewController);
351         mButtonSelectionStateController.addAllButtonsWithSelectionState(view);
352         mButtonRoleHolderController.addAllButtonsWithRoleName(view);
353         mUserNameViewControllerLazy.get().addUserNameView(view);
354         mPrivacyChipViewControllerLazy.get().addPrivacyChipView(view);
355     }
356 
setupMicQcPanel()357     private void setupMicQcPanel() {
358         if (mMicPanelController == null) {
359             mMicPanelController = new StatusIconPanelController(mContext, mCarServiceProvider,
360                     mBroadcastDispatcher, mConfigurationController);
361         }
362 
363         mMicPanelController.setOnQcViewsFoundListener(qcViews -> qcViews.forEach(qcView -> {
364             if (qcView.getLocalQCProvider() instanceof MicQcPanel) {
365                 MicQcPanel micQcPanel = (MicQcPanel) qcView.getLocalQCProvider();
366                 micQcPanel.setControllers(mPrivacyChipViewControllerLazy.get(),
367                         mMicPrivacyElementsProviderLazy.get());
368             }
369         }));
370 
371         mMicPanelController.attachPanel(mTopView.requireViewById(R.id.privacy_chip),
372                 R.layout.qc_mic_panel, R.dimen.car_mic_qc_panel_width, mPrivacyChipXOffset,
373                 mMicPanelController.getDefaultYOffset(), Gravity.TOP | Gravity.END);
374     }
375 
setupProfilePanel()376     private void setupProfilePanel() {
377         View profilePickerView = mTopView.findViewById(R.id.user_name);
378         if (mProfilePanelController == null && profilePickerView != null) {
379             boolean profilePanelDisabledWhileDriving = mContext.getResources().getBoolean(
380                     R.bool.config_profile_panel_disabled_while_driving);
381             mProfilePanelController = new StatusIconPanelController(mContext, mCarServiceProvider,
382                     mBroadcastDispatcher, mConfigurationController,
383                     profilePanelDisabledWhileDriving);
384             mProfilePanelController.attachPanel(profilePickerView, R.layout.qc_profile_switcher,
385                     R.dimen.car_profile_quick_controls_panel_width, Gravity.TOP | Gravity.END);
386         }
387     }
388 
389     /** Sets a touch listener for the top navigation bar. */
registerTopBarTouchListener(View.OnTouchListener listener)390     public void registerTopBarTouchListener(View.OnTouchListener listener) {
391         mTopBarTouchListener = listener;
392         if (mTopView != null) {
393             mTopView.setStatusBarWindowTouchListener(mTopBarTouchListener);
394         }
395     }
396 
397     /** Sets a touch listener for the bottom navigation bar. */
registerBottomBarTouchListener(View.OnTouchListener listener)398     public void registerBottomBarTouchListener(View.OnTouchListener listener) {
399         mBottomBarTouchListener = listener;
400         if (mBottomView != null) {
401             mBottomView.setStatusBarWindowTouchListener(mBottomBarTouchListener);
402         }
403     }
404 
405     /** Sets a touch listener for the left navigation bar. */
registerLeftBarTouchListener(View.OnTouchListener listener)406     public void registerLeftBarTouchListener(View.OnTouchListener listener) {
407         mLeftBarTouchListener = listener;
408         if (mLeftView != null) {
409             mLeftView.setStatusBarWindowTouchListener(mLeftBarTouchListener);
410         }
411     }
412 
413     /** Sets a touch listener for the right navigation bar. */
registerRightBarTouchListener(View.OnTouchListener listener)414     public void registerRightBarTouchListener(View.OnTouchListener listener) {
415         mRightBarTouchListener = listener;
416         if (mRightView != null) {
417             mRightView.setStatusBarWindowTouchListener(mRightBarTouchListener);
418         }
419     }
420 
421     /** Sets a notification controller which toggles the notification panel. */
registerNotificationController( NotificationsShadeController notificationsShadeController)422     public void registerNotificationController(
423             NotificationsShadeController notificationsShadeController) {
424         mNotificationsShadeController = notificationsShadeController;
425         if (mTopView != null) {
426             mTopView.setNotificationsPanelController(mNotificationsShadeController);
427         }
428         if (mBottomView != null) {
429             mBottomView.setNotificationsPanelController(mNotificationsShadeController);
430         }
431         if (mLeftView != null) {
432             mLeftView.setNotificationsPanelController(mNotificationsShadeController);
433         }
434         if (mRightView != null) {
435             mRightView.setNotificationsPanelController(mNotificationsShadeController);
436         }
437     }
438 
439     /** Sets an HVAC controller which toggles the HVAC panel. */
registerHvacPanelController(HvacPanelController hvacPanelController)440     public void registerHvacPanelController(HvacPanelController hvacPanelController) {
441         mHvacPanelController = hvacPanelController;
442         if (mTopView != null) {
443             mTopView.setHvacPanelController(mHvacPanelController);
444         }
445         if (mBottomView != null) {
446             mBottomView.setHvacPanelController(mHvacPanelController);
447         }
448         if (mLeftView != null) {
449             mLeftView.setHvacPanelController(mHvacPanelController);
450         }
451         if (mRightView != null) {
452             mRightView.setHvacPanelController(mHvacPanelController);
453         }
454     }
455 
456     /** Sets the HVACPanelOverlayViewController for views to listen to the panel's state. */
registerHvacPanelOverlayViewController( HvacPanelOverlayViewController hvacPanelOverlayViewController)457     public void registerHvacPanelOverlayViewController(
458             HvacPanelOverlayViewController hvacPanelOverlayViewController) {
459         mHvacPanelOverlayViewController = hvacPanelOverlayViewController;
460         if (mTopView != null) {
461             mTopView.registerHvacPanelOverlayViewController(mHvacPanelOverlayViewController);
462         }
463         if (mBottomView != null) {
464             mBottomView.registerHvacPanelOverlayViewController(mHvacPanelOverlayViewController);
465         }
466         if (mLeftView != null) {
467             mLeftView.registerHvacPanelOverlayViewController(mHvacPanelOverlayViewController);
468         }
469         if (mRightView != null) {
470             mRightView.registerHvacPanelOverlayViewController(mHvacPanelOverlayViewController);
471         }
472     }
473 
474     /**
475      * Shows all of the navigation buttons on the valid instances of {@link CarSystemBarView}.
476      */
showAllNavigationButtons(boolean isSetUp)477     public void showAllNavigationButtons(boolean isSetUp) {
478         checkAllBars(isSetUp);
479         if (mTopView != null) {
480             mTopView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_NAVIGATION);
481         }
482         if (mBottomView != null) {
483             mBottomView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_NAVIGATION);
484         }
485         if (mLeftView != null) {
486             mLeftView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_NAVIGATION);
487         }
488         if (mRightView != null) {
489             mRightView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_NAVIGATION);
490         }
491     }
492 
493     /**
494      * Shows all of the keyguard specific buttons on the valid instances of
495      * {@link CarSystemBarView}.
496      */
showAllKeyguardButtons(boolean isSetUp)497     public void showAllKeyguardButtons(boolean isSetUp) {
498         checkAllBars(isSetUp);
499         if (mTopView != null) {
500             mTopView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_KEYGUARD);
501         }
502         if (mBottomView != null) {
503             mBottomView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_KEYGUARD);
504         }
505         if (mLeftView != null) {
506             mLeftView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_KEYGUARD);
507         }
508         if (mRightView != null) {
509             mRightView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_KEYGUARD);
510         }
511     }
512 
513     /**
514      * Shows all of the occlusion state buttons on the valid instances of
515      * {@link CarSystemBarView}.
516      */
showAllOcclusionButtons(boolean isSetUp)517     public void showAllOcclusionButtons(boolean isSetUp) {
518         checkAllBars(isSetUp);
519         if (mTopView != null) {
520             mTopView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_OCCLUSION);
521         }
522         if (mBottomView != null) {
523             mBottomView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_OCCLUSION);
524         }
525         if (mLeftView != null) {
526             mLeftView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_OCCLUSION);
527         }
528         if (mRightView != null) {
529             mRightView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_OCCLUSION);
530         }
531     }
532 
533     /** Toggles whether the notifications icon has an unseen indicator or not. */
toggleAllNotificationsUnseenIndicator(boolean isSetUp, boolean hasUnseen)534     public void toggleAllNotificationsUnseenIndicator(boolean isSetUp, boolean hasUnseen) {
535         checkAllBars(isSetUp);
536         if (mTopView != null) {
537             mTopView.toggleNotificationUnseenIndicator(hasUnseen);
538         }
539         if (mBottomView != null) {
540             mBottomView.toggleNotificationUnseenIndicator(hasUnseen);
541         }
542         if (mLeftView != null) {
543             mLeftView.toggleNotificationUnseenIndicator(hasUnseen);
544         }
545         if (mRightView != null) {
546             mRightView.toggleNotificationUnseenIndicator(hasUnseen);
547         }
548     }
549 
550     /** Interface for controlling the notifications shade. */
551     public interface NotificationsShadeController {
552         /** Toggles the visibility of the notifications shade. */
togglePanel()553         void togglePanel();
554 
555         /** Returns {@code true} if the panel is open. */
isNotificationPanelOpen()556         boolean isNotificationPanelOpen();
557     }
558 
559     /** Interface for controlling the HVAC panel. */
560     public interface HvacPanelController {
561         /** Toggles the visibility of the HVAC shade. */
togglePanel()562         void togglePanel();
563 
564         /** Returns {@code true} if the panel is open. */
isHvacPanelOpen()565         boolean isHvacPanelOpen();
566     }
567 
checkAllBars(boolean isSetUp)568     private void checkAllBars(boolean isSetUp) {
569         mTopView = getTopBar(isSetUp);
570         mBottomView = getBottomBar(isSetUp);
571         mLeftView = getLeftBar(isSetUp);
572         mRightView = getRightBar(isSetUp);
573     }
574 
getAllAvailableSystemBarViews()575     private List<CarSystemBarView> getAllAvailableSystemBarViews() {
576         List<CarSystemBarView> barViews = new ArrayList<>();
577         if (mTopView != null) {
578             barViews.add(mTopView);
579         }
580         if (mBottomView != null) {
581             barViews.add(mBottomView);
582         }
583         if (mLeftView != null) {
584             barViews.add(mLeftView);
585         }
586         if (mRightView != null) {
587             barViews.add(mRightView);
588         }
589         return barViews;
590     }
591 }
592