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