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