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 com.android.systemui.car.systembar.SystemBarConfigs.BOTTOM; 20 import static com.android.systemui.car.systembar.SystemBarConfigs.LEFT; 21 import static com.android.systemui.car.systembar.SystemBarConfigs.RIGHT; 22 import static com.android.systemui.car.systembar.SystemBarConfigs.TOP; 23 24 import android.annotation.LayoutRes; 25 import android.app.ActivityManager; 26 import android.app.StatusBarManager; 27 import android.content.Context; 28 import android.os.Build; 29 import android.util.ArraySet; 30 import android.util.Log; 31 import android.view.Gravity; 32 import android.view.View; 33 import android.view.ViewGroup; 34 import android.widget.Toast; 35 36 import androidx.annotation.IdRes; 37 import androidx.annotation.Nullable; 38 39 import com.android.car.ui.FocusParkingView; 40 import com.android.car.ui.utils.ViewUtils; 41 import com.android.internal.annotations.VisibleForTesting; 42 import com.android.systemui.R; 43 import com.android.systemui.car.hvac.HvacPanelOverlayViewController; 44 import com.android.systemui.car.notification.NotificationPanelViewController; 45 import com.android.systemui.car.statusbar.UserNameViewController; 46 import com.android.systemui.car.statusicon.StatusIconPanelViewController; 47 import com.android.systemui.car.users.CarSystemUIUserUtil; 48 import com.android.systemui.dagger.SysUISingleton; 49 import com.android.systemui.settings.UserTracker; 50 51 import dagger.Lazy; 52 53 import java.util.ArrayList; 54 import java.util.List; 55 import java.util.Set; 56 57 import javax.inject.Provider; 58 59 /** A single class which controls the navigation bar views. */ 60 @SysUISingleton 61 public class CarSystemBarController { 62 private static final boolean DEBUG = Build.IS_ENG || Build.IS_USERDEBUG; 63 64 private static final String TAG = CarSystemBarController.class.getSimpleName(); 65 66 private final Context mContext; 67 private final UserTracker mUserTracker; 68 private final CarSystemBarViewFactory mCarSystemBarViewFactory; 69 private final ButtonSelectionStateController mButtonSelectionStateController; 70 private final ButtonRoleHolderController mButtonRoleHolderController; 71 private final Provider<StatusIconPanelViewController.Builder> mPanelControllerBuilderProvider; 72 private final Lazy<UserNameViewController> mUserNameViewControllerLazy; 73 private final Lazy<MicPrivacyChipViewController> mMicPrivacyChipViewControllerLazy; 74 private final Lazy<CameraPrivacyChipViewController> mCameraPrivacyChipViewControllerLazy; 75 76 private final SystemBarConfigs mSystemBarConfigs; 77 private boolean mShowTop; 78 private boolean mShowBottom; 79 private boolean mShowLeft; 80 private boolean mShowRight; 81 private final int mPrivacyChipXOffset; 82 83 @IdRes 84 private int mTopFocusedViewId; 85 @IdRes 86 private int mBottomFocusedViewId; 87 @IdRes 88 private int mLeftFocusedViewId; 89 @IdRes 90 private int mRightFocusedViewId; 91 92 private final Set<View.OnTouchListener> mTopBarTouchListeners = new ArraySet<>(); 93 private final Set<View.OnTouchListener> mBottomBarTouchListeners = new ArraySet<>(); 94 private final Set<View.OnTouchListener> mLeftBarTouchListeners = new ArraySet<>(); 95 private final Set<View.OnTouchListener> mRightBarTouchListeners = new ArraySet<>(); 96 97 private NotificationsShadeController mNotificationsShadeController; 98 private HvacPanelController mHvacPanelController; 99 private StatusIconPanelViewController mMicPanelController; 100 private StatusIconPanelViewController mCameraPanelController; 101 private StatusIconPanelViewController mProfilePanelController; 102 private HvacPanelOverlayViewController mHvacPanelOverlayViewController; 103 private NotificationPanelViewController mNotificationPanelViewController; 104 105 private CarSystemBarView mTopView; 106 private CarSystemBarView mBottomView; 107 private CarSystemBarView mLeftView; 108 private CarSystemBarView mRightView; 109 110 // Saved StatusBarManager.DisableFlags 111 private int mStatusBarState; 112 // Saved StatusBarManager.Disable2Flags 113 private int mStatusBarState2; 114 private int mLockTaskMode; 115 CarSystemBarController(Context context, UserTracker userTracker, CarSystemBarViewFactory carSystemBarViewFactory, ButtonSelectionStateController buttonSelectionStateController, Lazy<UserNameViewController> userNameViewControllerLazy, Lazy<MicPrivacyChipViewController> micPrivacyChipViewControllerLazy, Lazy<CameraPrivacyChipViewController> cameraPrivacyChipViewControllerLazy, ButtonRoleHolderController buttonRoleHolderController, SystemBarConfigs systemBarConfigs, Provider<StatusIconPanelViewController.Builder> panelControllerBuilderProvider)116 public CarSystemBarController(Context context, 117 UserTracker userTracker, 118 CarSystemBarViewFactory carSystemBarViewFactory, 119 ButtonSelectionStateController buttonSelectionStateController, 120 Lazy<UserNameViewController> userNameViewControllerLazy, 121 Lazy<MicPrivacyChipViewController> micPrivacyChipViewControllerLazy, 122 Lazy<CameraPrivacyChipViewController> cameraPrivacyChipViewControllerLazy, 123 ButtonRoleHolderController buttonRoleHolderController, 124 SystemBarConfigs systemBarConfigs, 125 Provider<StatusIconPanelViewController.Builder> panelControllerBuilderProvider) { 126 mContext = context; 127 mUserTracker = userTracker; 128 mCarSystemBarViewFactory = carSystemBarViewFactory; 129 mButtonSelectionStateController = buttonSelectionStateController; 130 mUserNameViewControllerLazy = userNameViewControllerLazy; 131 mMicPrivacyChipViewControllerLazy = micPrivacyChipViewControllerLazy; 132 mCameraPrivacyChipViewControllerLazy = cameraPrivacyChipViewControllerLazy; 133 mButtonRoleHolderController = buttonRoleHolderController; 134 mPanelControllerBuilderProvider = panelControllerBuilderProvider; 135 mSystemBarConfigs = systemBarConfigs; 136 137 // Read configuration. 138 readConfigs(); 139 mPrivacyChipXOffset = -context.getResources() 140 .getDimensionPixelOffset(R.dimen.privacy_chip_horizontal_padding); 141 } 142 readConfigs()143 private void readConfigs() { 144 mShowTop = mSystemBarConfigs.getEnabledStatusBySide(TOP); 145 mShowBottom = mSystemBarConfigs.getEnabledStatusBySide(BOTTOM); 146 mShowLeft = mSystemBarConfigs.getEnabledStatusBySide(LEFT); 147 mShowRight = mSystemBarConfigs.getEnabledStatusBySide(RIGHT); 148 } 149 150 /** 151 * Hides all system bars. 152 */ hideBars()153 public void hideBars() { 154 setTopWindowVisibility(View.GONE); 155 setBottomWindowVisibility(View.GONE); 156 setLeftWindowVisibility(View.GONE); 157 setRightWindowVisibility(View.GONE); 158 } 159 160 /** 161 * Shows all system bars. 162 */ showBars()163 public void showBars() { 164 setTopWindowVisibility(View.VISIBLE); 165 setBottomWindowVisibility(View.VISIBLE); 166 setLeftWindowVisibility(View.VISIBLE); 167 setRightWindowVisibility(View.VISIBLE); 168 } 169 170 /** Clean up */ removeAll()171 public void removeAll() { 172 mButtonSelectionStateController.removeAll(); 173 mButtonRoleHolderController.removeAll(); 174 mUserNameViewControllerLazy.get().removeAll(); 175 mMicPrivacyChipViewControllerLazy.get().removeAll(); 176 mCameraPrivacyChipViewControllerLazy.get().removeAll(); 177 178 mMicPanelController = null; 179 mCameraPanelController = null; 180 mProfilePanelController = null; 181 } 182 183 /** Gets the top window if configured to do so. */ 184 @Nullable getTopWindow()185 public ViewGroup getTopWindow() { 186 return mShowTop ? mCarSystemBarViewFactory.getTopWindow() : null; 187 } 188 189 /** Gets the bottom window if configured to do so. */ 190 @Nullable getBottomWindow()191 public ViewGroup getBottomWindow() { 192 return mShowBottom ? mCarSystemBarViewFactory.getBottomWindow() : null; 193 } 194 195 /** Gets the left window if configured to do so. */ 196 @Nullable getLeftWindow()197 public ViewGroup getLeftWindow() { 198 return mShowLeft ? mCarSystemBarViewFactory.getLeftWindow() : null; 199 } 200 201 /** Gets the right window if configured to do so. */ 202 @Nullable getRightWindow()203 public ViewGroup getRightWindow() { 204 return mShowRight ? mCarSystemBarViewFactory.getRightWindow() : null; 205 } 206 207 /** Toggles the top nav bar visibility. */ setTopWindowVisibility(@iew.Visibility int visibility)208 public boolean setTopWindowVisibility(@View.Visibility int visibility) { 209 return setWindowVisibility(getTopWindow(), visibility); 210 } 211 212 /** Toggles the bottom nav bar visibility. */ setBottomWindowVisibility(@iew.Visibility int visibility)213 public boolean setBottomWindowVisibility(@View.Visibility int visibility) { 214 return setWindowVisibility(getBottomWindow(), visibility); 215 } 216 217 /** Toggles the left nav bar visibility. */ setLeftWindowVisibility(@iew.Visibility int visibility)218 public boolean setLeftWindowVisibility(@View.Visibility int visibility) { 219 return setWindowVisibility(getLeftWindow(), visibility); 220 } 221 222 /** Toggles the right nav bar visibility. */ setRightWindowVisibility(@iew.Visibility int visibility)223 public boolean setRightWindowVisibility(@View.Visibility int visibility) { 224 return setWindowVisibility(getRightWindow(), visibility); 225 } 226 setWindowVisibility(ViewGroup window, @View.Visibility int visibility)227 private boolean setWindowVisibility(ViewGroup window, @View.Visibility int visibility) { 228 if (window == null) { 229 return false; 230 } 231 232 if (window.getVisibility() == visibility) { 233 return false; 234 } 235 236 window.setVisibility(visibility); 237 return true; 238 } 239 240 /** 241 * Sets the system bar states - {@code StatusBarManager.DisableFlags}, 242 * {@code StatusBarManager.Disable2Flags}, lock task mode. When there is a change in state, 243 * and refreshes the system bars. 244 * 245 * @param state {@code StatusBarManager.DisableFlags} 246 * @param state2 {@code StatusBarManager.Disable2Flags} 247 */ setSystemBarStates(int state, int state2)248 public void setSystemBarStates(int state, int state2) { 249 int diff = (state ^ mStatusBarState) | (state2 ^ mStatusBarState2); 250 int lockTaskMode = getLockTaskModeState(); 251 if (diff == 0 && mLockTaskMode == lockTaskMode) { 252 if (DEBUG) { 253 Log.d(TAG, "setSystemBarStates(): status bar states unchanged: state: " 254 + state + " state2: " + state2 + " lockTaskMode: " + mLockTaskMode); 255 } 256 return; 257 } 258 mStatusBarState = state; 259 mStatusBarState2 = state2; 260 mLockTaskMode = lockTaskMode; 261 refreshSystemBar(); 262 } 263 264 @VisibleForTesting getStatusBarState()265 protected int getStatusBarState() { 266 return mStatusBarState; 267 } 268 269 @VisibleForTesting getStatusBarState2()270 protected int getStatusBarState2() { 271 return mStatusBarState2; 272 } 273 274 @VisibleForTesting getLockTaskMode()275 protected int getLockTaskMode() { 276 return mLockTaskMode; 277 } 278 279 /** 280 * Refreshes system bar views and sets the visibility of certain components based on 281 * {@link StatusBarManager} flags and lock task mode. 282 * <ul> 283 * <li>Home button will be disabled when {@code StatusBarManager.DISABLE_HOME} is set. 284 * <li>Phone call button will be disable in lock task mode. 285 * <li>App grid button will be disable when {@code StatusBarManager.DISABLE_HOME} is set. 286 * <li>Notification button will be disable when 287 * {@code StatusBarManager.DISABLE_NOTIFICATION_ICONS} is set. 288 * <li>Quick settings and user switcher will be hidden when in lock task mode or when 289 * {@code StatusBarManager.DISABLE2_QUICK_SETTINGS} is set. 290 * </ul> 291 */ refreshSystemBar()292 public void refreshSystemBar() { 293 boolean homeDisabled = ((mStatusBarState & StatusBarManager.DISABLE_HOME) > 0); 294 boolean notificationDisabled = 295 ((mStatusBarState & StatusBarManager.DISABLE_NOTIFICATION_ICONS) > 0); 296 boolean locked = (mLockTaskMode == ActivityManager.LOCK_TASK_MODE_LOCKED); 297 boolean qcDisabled = 298 ((mStatusBarState2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) > 0) || locked; 299 boolean systemIconsDisabled = 300 ((mStatusBarState2 & StatusBarManager.DISABLE2_SYSTEM_ICONS) > 0) || locked; 301 302 setDisabledSystemBarButton(R.id.home, homeDisabled, "home"); 303 setDisabledSystemBarButton(R.id.passenger_home, homeDisabled, "passenger_home"); 304 setDisabledSystemBarButton(R.id.phone_nav, locked, "phone_nav"); 305 setDisabledSystemBarButton(R.id.grid_nav, homeDisabled, "grid_nav"); 306 setDisabledSystemBarButton(R.id.notifications, notificationDisabled, "notifications"); 307 308 setDisabledSystemBarContainer(R.id.user_name_container, qcDisabled, 309 "user_name_container"); 310 311 if (DEBUG) { 312 Log.d(TAG, "refreshSystemBar: locked?: " + locked 313 + " homeDisabled: " + homeDisabled 314 + " notificationDisabled: " + notificationDisabled 315 + " qcDisabled: " + qcDisabled 316 + " systemIconsDisabled: " + systemIconsDisabled); 317 } 318 } 319 getLockTaskModeState()320 private int getLockTaskModeState() { 321 return mContext.getSystemService(ActivityManager.class).getLockTaskModeState(); 322 } 323 setDisabledSystemBarButton(int viewId, boolean disabled, @Nullable String buttonName)324 private void setDisabledSystemBarButton(int viewId, boolean disabled, 325 @Nullable String buttonName) { 326 for (CarSystemBarView barView : getAllAvailableSystemBarViews()) { 327 barView.setDisabledSystemBarButton(viewId, disabled, 328 () -> showAdminSupportDetailsDialog(), buttonName); 329 } 330 } 331 setDisabledSystemBarContainer(int viewId, boolean disabled, @Nullable String viewName)332 private void setDisabledSystemBarContainer(int viewId, boolean disabled, 333 @Nullable String viewName) { 334 for (CarSystemBarView barView : getAllAvailableSystemBarViews()) { 335 barView.setVisibilityByViewId(viewId, viewName, 336 disabled ? View.INVISIBLE : View.VISIBLE); 337 } 338 } 339 showAdminSupportDetailsDialog()340 private void showAdminSupportDetailsDialog() { 341 // TODO(b/205891123): launch AdminSupportDetailsDialog after moving 342 // AdminSupportDetailsDialog out of CarSettings since CarSettings is not and should not 343 // be allowlisted for lock task mode. 344 Toast.makeText(mContext, "This action is unavailable for your profile", 345 Toast.LENGTH_LONG).show(); 346 } 347 348 /** Gets the top navigation bar with the appropriate listeners set. */ 349 @Nullable getTopBar(boolean isSetUp)350 public CarSystemBarView getTopBar(boolean isSetUp) { 351 if (!mShowTop) { 352 return null; 353 } 354 355 mTopView = mCarSystemBarViewFactory.getTopBar(isSetUp); 356 setupBar(mTopView, mTopBarTouchListeners, mNotificationsShadeController, 357 mHvacPanelController, mHvacPanelOverlayViewController, 358 mNotificationPanelViewController); 359 360 if (isSetUp) { 361 // We do not want the privacy chips or the profile picker to be clickable in 362 // unprovisioned mode. 363 mMicPanelController = setupSensorQcPanel(mMicPanelController, R.id.mic_privacy_chip, 364 R.layout.qc_mic_panel); 365 mCameraPanelController = setupSensorQcPanel(mCameraPanelController, 366 R.id.camera_privacy_chip, R.layout.qc_camera_panel); 367 setupProfilePanel(); 368 } 369 370 return mTopView; 371 } 372 373 /** Gets the bottom navigation bar with the appropriate listeners set. */ 374 @Nullable getBottomBar(boolean isSetUp)375 public CarSystemBarView getBottomBar(boolean isSetUp) { 376 if (!mShowBottom) { 377 return null; 378 } 379 380 mBottomView = mCarSystemBarViewFactory.getBottomBar(isSetUp); 381 setupBar(mBottomView, mBottomBarTouchListeners, mNotificationsShadeController, 382 mHvacPanelController, mHvacPanelOverlayViewController, 383 mNotificationPanelViewController); 384 385 return mBottomView; 386 } 387 388 /** Gets the left navigation bar with the appropriate listeners set. */ 389 @Nullable getLeftBar(boolean isSetUp)390 public CarSystemBarView getLeftBar(boolean isSetUp) { 391 if (!mShowLeft) { 392 return null; 393 } 394 395 mLeftView = mCarSystemBarViewFactory.getLeftBar(isSetUp); 396 setupBar(mLeftView, mLeftBarTouchListeners, mNotificationsShadeController, 397 mHvacPanelController, mHvacPanelOverlayViewController, 398 mNotificationPanelViewController); 399 return mLeftView; 400 } 401 402 /** Gets the right navigation bar with the appropriate listeners set. */ 403 @Nullable getRightBar(boolean isSetUp)404 public CarSystemBarView getRightBar(boolean isSetUp) { 405 if (!mShowRight) { 406 return null; 407 } 408 409 mRightView = mCarSystemBarViewFactory.getRightBar(isSetUp); 410 setupBar(mRightView, mRightBarTouchListeners, mNotificationsShadeController, 411 mHvacPanelController, mHvacPanelOverlayViewController, 412 mNotificationPanelViewController); 413 return mRightView; 414 } 415 setupBar(CarSystemBarView view, Set<View.OnTouchListener> statusBarTouchListeners, NotificationsShadeController notifShadeController, HvacPanelController hvacPanelController, HvacPanelOverlayViewController hvacPanelOverlayViewController, NotificationPanelViewController notificationPanelViewController)416 private void setupBar(CarSystemBarView view, Set<View.OnTouchListener> statusBarTouchListeners, 417 NotificationsShadeController notifShadeController, 418 HvacPanelController hvacPanelController, 419 HvacPanelOverlayViewController hvacPanelOverlayViewController, 420 NotificationPanelViewController notificationPanelViewController) { 421 view.updateHomeButtonVisibility(CarSystemUIUserUtil.isSecondaryMUMDSystemUI()); 422 view.setStatusBarWindowTouchListeners(statusBarTouchListeners); 423 view.setNotificationsPanelController(notifShadeController); 424 view.registerNotificationPanelViewController(notificationPanelViewController); 425 view.setHvacPanelController(hvacPanelController); 426 view.registerHvacPanelOverlayViewController(hvacPanelOverlayViewController); 427 view.updateControlCenterButtonVisibility(CarSystemUIUserUtil.isMUMDSystemUI()); 428 mButtonSelectionStateController.addAllButtonsWithSelectionState(view); 429 mButtonRoleHolderController.addAllButtonsWithRoleName(view); 430 mUserNameViewControllerLazy.get().addUserNameView(view); 431 mMicPrivacyChipViewControllerLazy.get().addPrivacyChipView(view); 432 mCameraPrivacyChipViewControllerLazy.get().addPrivacyChipView(view); 433 } 434 setupSensorQcPanel( @ullable StatusIconPanelViewController panelController, int chipId, @LayoutRes int panelLayoutRes)435 private StatusIconPanelViewController setupSensorQcPanel( 436 @Nullable StatusIconPanelViewController panelController, int chipId, 437 @LayoutRes int panelLayoutRes) { 438 if (panelController == null) { 439 View privacyChip = mTopView.findViewById(chipId); 440 if (privacyChip != null) { 441 panelController = mPanelControllerBuilderProvider.get() 442 .setXOffset(mPrivacyChipXOffset) 443 .setGravity(Gravity.TOP | Gravity.END) 444 .build(privacyChip, panelLayoutRes, R.dimen.car_sensor_qc_panel_width); 445 panelController.init(); 446 } 447 } 448 return panelController; 449 } 450 setupProfilePanel()451 private void setupProfilePanel() { 452 View profilePickerView = mTopView.findViewById(R.id.user_name); 453 if (mProfilePanelController == null && profilePickerView != null) { 454 boolean profilePanelDisabledWhileDriving = mContext.getResources().getBoolean( 455 R.bool.config_profile_panel_disabled_while_driving); 456 mProfilePanelController = mPanelControllerBuilderProvider.get() 457 .setGravity(Gravity.TOP | Gravity.END) 458 .setDisabledWhileDriving(profilePanelDisabledWhileDriving) 459 .build(profilePickerView, R.layout.qc_profile_switcher, 460 R.dimen.car_profile_quick_controls_panel_width); 461 mProfilePanelController.init(); 462 } 463 } 464 465 /** Sets a touch listener for the top navigation bar. */ registerTopBarTouchListener(View.OnTouchListener listener)466 public void registerTopBarTouchListener(View.OnTouchListener listener) { 467 boolean setModified = mTopBarTouchListeners.add(listener); 468 if (setModified && mTopView != null) { 469 mTopView.setStatusBarWindowTouchListeners(mTopBarTouchListeners); 470 } 471 } 472 473 /** Sets a touch listener for the bottom navigation bar. */ registerBottomBarTouchListener(View.OnTouchListener listener)474 public void registerBottomBarTouchListener(View.OnTouchListener listener) { 475 boolean setModified = mBottomBarTouchListeners.add(listener); 476 if (setModified && mBottomView != null) { 477 mBottomView.setStatusBarWindowTouchListeners(mBottomBarTouchListeners); 478 } 479 } 480 481 /** Sets a touch listener for the left navigation bar. */ registerLeftBarTouchListener(View.OnTouchListener listener)482 public void registerLeftBarTouchListener(View.OnTouchListener listener) { 483 boolean setModified = mLeftBarTouchListeners.add(listener); 484 if (setModified && mLeftView != null) { 485 mLeftView.setStatusBarWindowTouchListeners(mLeftBarTouchListeners); 486 } 487 } 488 489 /** Sets a touch listener for the right navigation bar. */ registerRightBarTouchListener(View.OnTouchListener listener)490 public void registerRightBarTouchListener(View.OnTouchListener listener) { 491 boolean setModified = mRightBarTouchListeners.add(listener); 492 if (setModified && mRightView != null) { 493 mRightView.setStatusBarWindowTouchListeners(mRightBarTouchListeners); 494 } 495 } 496 497 /** Sets a notification controller which toggles the notification panel. */ registerNotificationController( NotificationsShadeController notificationsShadeController)498 public void registerNotificationController( 499 NotificationsShadeController notificationsShadeController) { 500 mNotificationsShadeController = notificationsShadeController; 501 if (mTopView != null) { 502 mTopView.setNotificationsPanelController(mNotificationsShadeController); 503 } 504 if (mBottomView != null) { 505 mBottomView.setNotificationsPanelController(mNotificationsShadeController); 506 } 507 if (mLeftView != null) { 508 mLeftView.setNotificationsPanelController(mNotificationsShadeController); 509 } 510 if (mRightView != null) { 511 mRightView.setNotificationsPanelController(mNotificationsShadeController); 512 } 513 } 514 515 /** Sets the NotificationPanelViewController for views to listen to the panel's state. */ registerNotificationPanelViewController( NotificationPanelViewController notificationPanelViewController)516 public void registerNotificationPanelViewController( 517 NotificationPanelViewController notificationPanelViewController) { 518 mNotificationPanelViewController = notificationPanelViewController; 519 if (mTopView != null) { 520 mTopView.registerNotificationPanelViewController(mNotificationPanelViewController); 521 } 522 if (mBottomView != null) { 523 mBottomView.registerNotificationPanelViewController(mNotificationPanelViewController); 524 } 525 if (mLeftView != null) { 526 mLeftView.registerNotificationPanelViewController(mNotificationPanelViewController); 527 } 528 if (mRightView != null) { 529 mRightView.registerNotificationPanelViewController(mNotificationPanelViewController); 530 } 531 } 532 533 /** Sets an HVAC controller which toggles the HVAC panel. */ registerHvacPanelController(HvacPanelController hvacPanelController)534 public void registerHvacPanelController(HvacPanelController hvacPanelController) { 535 mHvacPanelController = hvacPanelController; 536 if (mTopView != null) { 537 mTopView.setHvacPanelController(mHvacPanelController); 538 } 539 if (mBottomView != null) { 540 mBottomView.setHvacPanelController(mHvacPanelController); 541 } 542 if (mLeftView != null) { 543 mLeftView.setHvacPanelController(mHvacPanelController); 544 } 545 if (mRightView != null) { 546 mRightView.setHvacPanelController(mHvacPanelController); 547 } 548 } 549 550 /** Sets the HVACPanelOverlayViewController for views to listen to the panel's state. */ registerHvacPanelOverlayViewController( HvacPanelOverlayViewController hvacPanelOverlayViewController)551 public void registerHvacPanelOverlayViewController( 552 HvacPanelOverlayViewController hvacPanelOverlayViewController) { 553 mHvacPanelOverlayViewController = hvacPanelOverlayViewController; 554 if (mTopView != null) { 555 mTopView.registerHvacPanelOverlayViewController(mHvacPanelOverlayViewController); 556 } 557 if (mBottomView != null) { 558 mBottomView.registerHvacPanelOverlayViewController(mHvacPanelOverlayViewController); 559 } 560 if (mLeftView != null) { 561 mLeftView.registerHvacPanelOverlayViewController(mHvacPanelOverlayViewController); 562 } 563 if (mRightView != null) { 564 mRightView.registerHvacPanelOverlayViewController(mHvacPanelOverlayViewController); 565 } 566 } 567 568 /** 569 * Shows all of the navigation buttons on the valid instances of {@link CarSystemBarView}. 570 */ showAllNavigationButtons(boolean isSetUp)571 public void showAllNavigationButtons(boolean isSetUp) { 572 checkAllBars(isSetUp); 573 if (mTopView != null) { 574 mTopView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_NAVIGATION); 575 } 576 if (mBottomView != null) { 577 mBottomView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_NAVIGATION); 578 } 579 if (mLeftView != null) { 580 mLeftView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_NAVIGATION); 581 } 582 if (mRightView != null) { 583 mRightView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_NAVIGATION); 584 } 585 } 586 587 /** 588 * Shows all of the keyguard specific buttons on the valid instances of 589 * {@link CarSystemBarView}. 590 */ showAllKeyguardButtons(boolean isSetUp)591 public void showAllKeyguardButtons(boolean isSetUp) { 592 checkAllBars(isSetUp); 593 if (mTopView != null) { 594 mTopView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_KEYGUARD); 595 } 596 if (mBottomView != null) { 597 mBottomView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_KEYGUARD); 598 } 599 if (mLeftView != null) { 600 mLeftView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_KEYGUARD); 601 } 602 if (mRightView != null) { 603 mRightView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_KEYGUARD); 604 } 605 } 606 607 /** 608 * Shows all of the occlusion state buttons on the valid instances of 609 * {@link CarSystemBarView}. 610 */ showAllOcclusionButtons(boolean isSetUp)611 public void showAllOcclusionButtons(boolean isSetUp) { 612 checkAllBars(isSetUp); 613 if (mTopView != null) { 614 mTopView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_OCCLUSION); 615 } 616 if (mBottomView != null) { 617 mBottomView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_OCCLUSION); 618 } 619 if (mLeftView != null) { 620 mLeftView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_OCCLUSION); 621 } 622 if (mRightView != null) { 623 mRightView.showButtonsOfType(CarSystemBarView.BUTTON_TYPE_OCCLUSION); 624 } 625 } 626 627 /** Toggles whether the notifications icon has an unseen indicator or not. */ toggleAllNotificationsUnseenIndicator(boolean isSetUp, boolean hasUnseen)628 public void toggleAllNotificationsUnseenIndicator(boolean isSetUp, boolean hasUnseen) { 629 checkAllBars(isSetUp); 630 if (mTopView != null) { 631 mTopView.toggleNotificationUnseenIndicator(hasUnseen); 632 } 633 if (mBottomView != null) { 634 mBottomView.toggleNotificationUnseenIndicator(hasUnseen); 635 } 636 if (mLeftView != null) { 637 mLeftView.toggleNotificationUnseenIndicator(hasUnseen); 638 } 639 if (mRightView != null) { 640 mRightView.toggleNotificationUnseenIndicator(hasUnseen); 641 } 642 } 643 644 /** Interface for controlling the notifications shade. */ 645 public interface NotificationsShadeController { 646 /** Toggles the visibility of the notifications shade. */ togglePanel()647 void togglePanel(); 648 649 /** Returns {@code true} if the panel is open. */ isNotificationPanelOpen()650 boolean isNotificationPanelOpen(); 651 } 652 653 /** Interface for controlling the HVAC panel. */ 654 public interface HvacPanelController { 655 /** Toggles the visibility of the HVAC shade. */ togglePanel()656 void togglePanel(); 657 658 /** Returns {@code true} if the panel is open. */ isHvacPanelOpen()659 boolean isHvacPanelOpen(); 660 } 661 checkAllBars(boolean isSetUp)662 private void checkAllBars(boolean isSetUp) { 663 mTopView = getTopBar(isSetUp); 664 mBottomView = getBottomBar(isSetUp); 665 mLeftView = getLeftBar(isSetUp); 666 mRightView = getRightBar(isSetUp); 667 } 668 getAllAvailableSystemBarViews()669 private List<CarSystemBarView> getAllAvailableSystemBarViews() { 670 List<CarSystemBarView> barViews = new ArrayList<>(); 671 if (mTopView != null) { 672 barViews.add(mTopView); 673 } 674 if (mBottomView != null) { 675 barViews.add(mBottomView); 676 } 677 if (mLeftView != null) { 678 barViews.add(mLeftView); 679 } 680 if (mRightView != null) { 681 barViews.add(mRightView); 682 } 683 return barViews; 684 } 685 686 /** Resets the cached Views. */ resetViewCache()687 protected void resetViewCache() { 688 mCarSystemBarViewFactory.resetSystemBarViewCache(); 689 } 690 691 /** 692 * Invalidate SystemBarConfigs and fetch again from Resources. 693 * TODO(): b/260206944, Can remove this after we have a fix for overlaid resources not applied. 694 */ resetSystemBarConfigs()695 protected void resetSystemBarConfigs() { 696 mSystemBarConfigs.resetSystemBarConfigs(); 697 mCarSystemBarViewFactory.resetSystemBarWindowCache(); 698 readConfigs(); 699 } 700 701 /** Stores the ID of the View that is currently focused and hides the focus. */ cacheAndHideFocus()702 protected void cacheAndHideFocus() { 703 mTopFocusedViewId = cacheAndHideFocus(mTopView); 704 if (mTopFocusedViewId != View.NO_ID) return; 705 mBottomFocusedViewId = cacheAndHideFocus(mBottomView); 706 if (mBottomFocusedViewId != View.NO_ID) return; 707 mLeftFocusedViewId = cacheAndHideFocus(mLeftView); 708 if (mLeftFocusedViewId != View.NO_ID) return; 709 mRightFocusedViewId = cacheAndHideFocus(mRightView); 710 } 711 712 @VisibleForTesting cacheAndHideFocus(@ullable View rootView)713 int cacheAndHideFocus(@Nullable View rootView) { 714 if (rootView == null) return View.NO_ID; 715 View focusedView = rootView.findFocus(); 716 if (focusedView == null || focusedView instanceof FocusParkingView) return View.NO_ID; 717 int focusedViewId = focusedView.getId(); 718 ViewUtils.hideFocus(rootView); 719 return focusedViewId; 720 } 721 722 /** Requests focus on the View that matches the cached ID. */ restoreFocus()723 protected void restoreFocus() { 724 if (restoreFocus(mTopView, mTopFocusedViewId)) return; 725 if (restoreFocus(mBottomView, mBottomFocusedViewId)) return; 726 if (restoreFocus(mLeftView, mLeftFocusedViewId)) return; 727 restoreFocus(mRightView, mRightFocusedViewId); 728 } 729 restoreFocus(@ullable View rootView, @IdRes int viewToFocusId)730 private boolean restoreFocus(@Nullable View rootView, @IdRes int viewToFocusId) { 731 if (rootView == null || viewToFocusId == View.NO_ID) return false; 732 View focusedView = rootView.findViewById(viewToFocusId); 733 if (focusedView == null) return false; 734 focusedView.requestFocus(); 735 return true; 736 } 737 } 738