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 android.content.Intent.ACTION_OVERLAY_CHANGED; 20 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; 21 22 import static com.android.systemui.car.Flags.configAwareSystemui; 23 import static com.android.systemui.car.systembar.SystemBarConfigs.BOTTOM; 24 import static com.android.systemui.car.systembar.SystemBarConfigs.LEFT; 25 import static com.android.systemui.car.systembar.SystemBarConfigs.RIGHT; 26 import static com.android.systemui.car.systembar.SystemBarConfigs.TOP; 27 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; 28 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 29 30 import android.annotation.Nullable; 31 import android.app.ActivityManager.RunningTaskInfo; 32 import android.app.StatusBarManager.Disable2Flags; 33 import android.app.StatusBarManager.DisableFlags; 34 import android.app.UiModeManager; 35 import android.content.BroadcastReceiver; 36 import android.content.Context; 37 import android.content.Intent; 38 import android.content.IntentFilter; 39 import android.content.res.Configuration; 40 import android.graphics.Rect; 41 import android.inputmethodservice.InputMethodService; 42 import android.os.IBinder; 43 import android.os.PatternMatcher; 44 import android.os.RemoteException; 45 import android.os.UserHandle; 46 import android.util.Log; 47 import android.view.View; 48 import android.view.ViewGroup; 49 import android.view.WindowInsets; 50 import android.view.WindowInsets.Type.InsetsType; 51 import android.view.WindowInsetsController; 52 import android.view.WindowManager; 53 54 import androidx.annotation.VisibleForTesting; 55 56 import com.android.internal.statusbar.IStatusBarService; 57 import com.android.internal.statusbar.LetterboxDetails; 58 import com.android.internal.statusbar.RegisterStatusBarResult; 59 import com.android.internal.view.AppearanceRegion; 60 import com.android.systemui.CoreStartable; 61 import com.android.systemui.R; 62 import com.android.systemui.car.CarDeviceProvisionedController; 63 import com.android.systemui.car.CarDeviceProvisionedListener; 64 import com.android.systemui.car.displaycompat.ToolbarController; 65 import com.android.systemui.car.hvac.HvacController; 66 import com.android.systemui.car.users.CarSystemUIUserUtil; 67 import com.android.systemui.dagger.SysUISingleton; 68 import com.android.systemui.dagger.qualifiers.Main; 69 import com.android.systemui.dagger.qualifiers.UiBackground; 70 import com.android.systemui.plugins.DarkIconDispatcher; 71 import com.android.systemui.settings.DisplayTracker; 72 import com.android.systemui.shared.system.TaskStackChangeListener; 73 import com.android.systemui.shared.system.TaskStackChangeListeners; 74 import com.android.systemui.statusbar.AutoHideUiElement; 75 import com.android.systemui.statusbar.CommandQueue; 76 import com.android.systemui.statusbar.phone.AutoHideController; 77 import com.android.systemui.statusbar.phone.BarTransitions; 78 import com.android.systemui.statusbar.phone.LightBarController; 79 import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; 80 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy; 81 import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher; 82 import com.android.systemui.statusbar.policy.ConfigurationController; 83 import com.android.systemui.statusbar.policy.KeyguardStateController; 84 import com.android.systemui.util.concurrency.DelayableExecutor; 85 import com.android.systemui.wm.MDSystemBarsController; 86 87 import dagger.Lazy; 88 89 import java.io.PrintWriter; 90 import java.util.ArrayList; 91 import java.util.Locale; 92 import java.util.Optional; 93 import java.util.concurrent.Executor; 94 95 import javax.inject.Inject; 96 97 /** Navigation bars customized for the automotive use case. */ 98 @SysUISingleton 99 public class CarSystemBar implements CoreStartable, CommandQueue.Callbacks, 100 ConfigurationController.ConfigurationListener, 101 MDSystemBarsController.Listener { 102 private static final String TAG = CarSystemBar.class.getSimpleName(); 103 private static final String OVERLAY_FILTER_DATA_SCHEME = "package"; 104 105 protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 106 107 private final Context mContext; 108 private final CarSystemBarController mCarSystemBarController; 109 private final SysuiDarkIconDispatcher mStatusBarIconController; 110 private final WindowManager mWindowManager; 111 private final CarDeviceProvisionedController mCarDeviceProvisionedController; 112 private final CommandQueue mCommandQueue; 113 private final AutoHideController mAutoHideController; 114 private final ButtonSelectionStateListener mButtonSelectionStateListener; 115 private final DelayableExecutor mExecutor; 116 private final Executor mUiBgExecutor; 117 private final IStatusBarService mBarService; 118 private final DisplayTracker mDisplayTracker; 119 private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy; 120 private final Lazy<PhoneStatusBarPolicy> mIconPolicyLazy; 121 private final HvacController mHvacController; 122 private final ConfigurationController mConfigurationController; 123 private final CarSystemBarRestartTracker mCarSystemBarRestartTracker; 124 private final int mDisplayId; 125 private final SystemBarConfigs mSystemBarConfigs; 126 @Nullable 127 private final ToolbarController mDisplayCompatToolbarController; 128 private UiModeManager mUiModeManager; 129 private StatusBarSignalPolicy mSignalPolicy; 130 131 // If the nav bar should be hidden when the soft keyboard is visible. 132 private boolean mHideTopBarForKeyboard; 133 private boolean mHideLeftBarForKeyboard; 134 private boolean mHideRightBarForKeyboard; 135 private boolean mHideBottomBarForKeyboard; 136 // Nav bar views. 137 private ViewGroup mTopSystemBarWindow; 138 private ViewGroup mBottomSystemBarWindow; 139 private ViewGroup mLeftSystemBarWindow; 140 private ViewGroup mRightSystemBarWindow; 141 private CarSystemBarView mTopSystemBarView; 142 private CarSystemBarView mBottomSystemBarView; 143 private CarSystemBarView mLeftSystemBarView; 144 private CarSystemBarView mRightSystemBarView; 145 private boolean mTopSystemBarAttached; 146 private boolean mBottomSystemBarAttached; 147 private boolean mLeftSystemBarAttached; 148 private boolean mRightSystemBarAttached; 149 150 // To be attached to the navigation bars such that they can close the notification panel if 151 // it's open. 152 private boolean mDeviceIsSetUpForUser = true; 153 private boolean mIsUserSetupInProgress = false; 154 155 private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0]; 156 @BarTransitions.TransitionMode 157 private int mStatusBarMode; 158 @BarTransitions.TransitionMode 159 private int mSystemBarMode; 160 private boolean mStatusBarTransientShown; 161 private boolean mNavBarTransientShown; 162 163 private boolean mIsUiModeNight = false; 164 private MDSystemBarsController mMDSystemBarsController; 165 166 private Locale mCurrentLocale; 167 168 @Inject CarSystemBar(Context context, CarSystemBarController carSystemBarController, LightBarController lightBarController, DarkIconDispatcher darkIconDispatcher, WindowManager windowManager, CarDeviceProvisionedController deviceProvisionedController, CommandQueue commandQueue, AutoHideController autoHideController, ButtonSelectionStateListener buttonSelectionStateListener, @Main DelayableExecutor mainExecutor, @UiBackground Executor uiBgExecutor, IStatusBarService barService, Lazy<KeyguardStateController> keyguardStateControllerLazy, Lazy<PhoneStatusBarPolicy> iconPolicyLazy, HvacController hvacController, StatusBarSignalPolicy signalPolicy, SystemBarConfigs systemBarConfigs, ConfigurationController configurationController, CarSystemBarRestartTracker restartTracker, DisplayTracker displayTracker, Optional<MDSystemBarsController> mdSystemBarsController, @Nullable ToolbarController toolbarController )169 public CarSystemBar(Context context, 170 CarSystemBarController carSystemBarController, 171 // TODO(b/156052638): Should not need to inject LightBarController 172 LightBarController lightBarController, 173 DarkIconDispatcher darkIconDispatcher, 174 WindowManager windowManager, 175 CarDeviceProvisionedController deviceProvisionedController, 176 CommandQueue commandQueue, 177 AutoHideController autoHideController, 178 ButtonSelectionStateListener buttonSelectionStateListener, 179 @Main DelayableExecutor mainExecutor, 180 @UiBackground Executor uiBgExecutor, 181 IStatusBarService barService, 182 Lazy<KeyguardStateController> keyguardStateControllerLazy, 183 Lazy<PhoneStatusBarPolicy> iconPolicyLazy, 184 HvacController hvacController, 185 StatusBarSignalPolicy signalPolicy, 186 SystemBarConfigs systemBarConfigs, 187 ConfigurationController configurationController, 188 CarSystemBarRestartTracker restartTracker, 189 DisplayTracker displayTracker, 190 Optional<MDSystemBarsController> mdSystemBarsController, 191 @Nullable ToolbarController toolbarController 192 ) { 193 mContext = context; 194 mCarSystemBarController = carSystemBarController; 195 mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher; 196 mWindowManager = windowManager; 197 mCarDeviceProvisionedController = deviceProvisionedController; 198 mCommandQueue = commandQueue; 199 mAutoHideController = autoHideController; 200 mButtonSelectionStateListener = buttonSelectionStateListener; 201 mExecutor = mainExecutor; 202 mUiBgExecutor = uiBgExecutor; 203 mBarService = barService; 204 mKeyguardStateControllerLazy = keyguardStateControllerLazy; 205 mIconPolicyLazy = iconPolicyLazy; 206 mHvacController = hvacController; 207 mSystemBarConfigs = systemBarConfigs; 208 mSignalPolicy = signalPolicy; 209 mDisplayId = context.getDisplayId(); 210 mUiModeManager = mContext.getSystemService(UiModeManager.class); 211 mDisplayTracker = displayTracker; 212 mIsUiModeNight = mContext.getResources().getConfiguration().isNightModeActive(); 213 mMDSystemBarsController = mdSystemBarsController.orElse(null); 214 mCurrentLocale = mContext.getResources().getConfiguration().getLocales().get(0); 215 mConfigurationController = configurationController; 216 mCarSystemBarRestartTracker = restartTracker; 217 mDisplayCompatToolbarController = toolbarController; 218 } 219 registerOverlayChangeBroadcastReceiver()220 private void registerOverlayChangeBroadcastReceiver() { 221 if (!configAwareSystemui()) { 222 if (DEBUG) { 223 Log.d(TAG, "Ignore overlay change for car systemui"); 224 } 225 return; 226 } 227 IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED); 228 overlayFilter.addDataScheme(OVERLAY_FILTER_DATA_SCHEME); 229 overlayFilter.addDataSchemeSpecificPart(mContext.getPackageName(), 230 PatternMatcher.PATTERN_LITERAL); 231 BroadcastReceiver receiver = new BroadcastReceiver() { 232 @Override 233 public void onReceive(Context context, Intent intent) { 234 if (mTopSystemBarAttached || mBottomSystemBarAttached || mLeftSystemBarAttached 235 || mRightSystemBarAttached) { 236 restartSystemBars(); 237 } 238 } 239 }; 240 mContext.registerReceiverAsUser(receiver, UserHandle.ALL, 241 overlayFilter, /* broadcastPermission= */null, /* handler= */ null); 242 } 243 244 @Override start()245 public void start() { 246 // Set initial state. 247 mHideTopBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(TOP); 248 mHideBottomBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(BOTTOM); 249 mHideLeftBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(LEFT); 250 mHideRightBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(RIGHT); 251 252 // Connect into the status bar manager service 253 mCommandQueue.addCallback(this); 254 255 RegisterStatusBarResult result = null; 256 //Register only for Primary User. 257 if (!CarSystemUIUserUtil.isSecondaryMUMDSystemUI()) { 258 try { 259 result = mBarService.registerStatusBar(mCommandQueue); 260 } catch (RemoteException ex) { 261 ex.rethrowFromSystemServer(); 262 } 263 } else if (mMDSystemBarsController != null) { 264 mMDSystemBarsController.addListener(this); 265 } 266 267 if (result != null) { 268 onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions, 269 result.mNavbarColorManagedByIme, result.mBehavior, 270 result.mRequestedVisibleTypes, 271 result.mPackageName, result.mLetterboxDetails); 272 273 // StatusBarManagerService has a back up of IME token and it's restored here. 274 setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis, 275 result.mImeBackDisposition, result.mShowImeSwitcher); 276 277 // Set up the initial icon state 278 int numIcons = result.mIcons.size(); 279 for (int i = 0; i < numIcons; i++) { 280 mCommandQueue.setIcon(result.mIcons.keyAt(i), result.mIcons.valueAt(i)); 281 } 282 } 283 284 mAutoHideController.setStatusBar(new AutoHideUiElement() { 285 @Override 286 public void synchronizeState() { 287 // No op. 288 } 289 290 @Override 291 public boolean isVisible() { 292 return mStatusBarTransientShown; 293 } 294 295 @Override 296 public void hide() { 297 clearTransient(); 298 } 299 }); 300 301 mAutoHideController.setNavigationBar(new AutoHideUiElement() { 302 @Override 303 public void synchronizeState() { 304 // No op. 305 } 306 307 @Override 308 public boolean isVisible() { 309 return mNavBarTransientShown; 310 } 311 312 @Override 313 public void hide() { 314 clearTransient(); 315 } 316 }); 317 318 mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup(); 319 mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress(); 320 mCarDeviceProvisionedController.addCallback( 321 new CarDeviceProvisionedListener() { 322 @Override 323 public void onUserSetupInProgressChanged() { 324 mExecutor.execute(() -> resetSystemBarContentIfNecessary()); 325 } 326 327 @Override 328 public void onUserSetupChanged() { 329 mExecutor.execute(() -> resetSystemBarContentIfNecessary()); 330 } 331 332 @Override 333 public void onUserSwitched() { 334 mExecutor.execute(() -> resetSystemBarContentIfNecessary()); 335 } 336 }); 337 338 mConfigurationController.addCallback(/* listener= */ this); 339 registerOverlayChangeBroadcastReceiver(); 340 341 createSystemBar(result); 342 343 TaskStackChangeListeners.getInstance().registerTaskStackListener( 344 mButtonSelectionStateListener); 345 TaskStackChangeListeners.getInstance().registerTaskStackListener( 346 new TaskStackChangeListener() { 347 @Override 348 public void onLockTaskModeChanged(int mode) { 349 mCarSystemBarController.refreshSystemBar(); 350 } 351 352 @Override 353 public void onTaskMovedToFront(RunningTaskInfo taskInfo) { 354 if (mDisplayCompatToolbarController != null) { 355 mDisplayCompatToolbarController.update(taskInfo); 356 } 357 } 358 }); 359 360 // Lastly, call to the icon policy to install/update all the icons. 361 // Must be called on the main thread due to the use of observeForever() in 362 // mIconPolicy.init(). 363 mExecutor.execute(() -> { 364 mIconPolicyLazy.get().init(); 365 }); 366 } 367 resetSystemBarContentIfNecessary()368 private void resetSystemBarContentIfNecessary() { 369 boolean currentUserSetup = mCarDeviceProvisionedController.isCurrentUserSetup(); 370 boolean currentUserSetupInProgress = mCarDeviceProvisionedController 371 .isCurrentUserSetupInProgress(); 372 if (mIsUserSetupInProgress != currentUserSetupInProgress 373 || mDeviceIsSetUpForUser != currentUserSetup) { 374 mDeviceIsSetUpForUser = currentUserSetup; 375 mIsUserSetupInProgress = currentUserSetupInProgress; 376 resetSystemBarContent(/* isProvisionedStateChange= */ true); 377 } 378 } 379 380 /** 381 * Remove all content from navbars and rebuild them. Used to allow for different nav bars 382 * before and after the device is provisioned. . Also for change of density and font size. 383 */ resetSystemBarContent(boolean isProvisionedStateChange)384 private void resetSystemBarContent(boolean isProvisionedStateChange) { 385 mCarSystemBarRestartTracker.notifyPendingRestart(/* recreateWindows= */ false, 386 isProvisionedStateChange); 387 388 if (!isProvisionedStateChange) { 389 mCarSystemBarController.resetViewCache(); 390 } 391 // remove and reattach all components such that we don't keep a reference to unused ui 392 // elements 393 mCarSystemBarController.removeAll(); 394 clearSystemBarWindow(/* removeUnusedWindow= */ false); 395 396 buildNavBarContent(); 397 // If the UI was rebuilt (day/night change or user change) while the keyguard was up we need 398 // to correctly respect that state. 399 if (mKeyguardStateControllerLazy.get().isShowing()) { 400 mCarSystemBarController.showAllKeyguardButtons(isDeviceSetupForUser()); 401 } else { 402 mCarSystemBarController.showAllNavigationButtons(isDeviceSetupForUser()); 403 } 404 405 // Upon restarting the Navigation Bar, CarFacetButtonController should immediately apply the 406 // selection state that reflects the current task stack. 407 mButtonSelectionStateListener.onTaskStackChanged(); 408 409 mCarSystemBarRestartTracker.notifyRestartComplete(/* recreateWindows= */ false, 410 isProvisionedStateChange); 411 } 412 isDeviceSetupForUser()413 private boolean isDeviceSetupForUser() { 414 return mDeviceIsSetUpForUser && !mIsUserSetupInProgress; 415 } 416 createSystemBar(RegisterStatusBarResult result)417 private void createSystemBar(RegisterStatusBarResult result) { 418 buildNavBarWindows(); 419 buildNavBarContent(); 420 attachNavBarWindows(); 421 422 // Try setting up the initial state of the nav bar if applicable. 423 if (result != null) { 424 setImeWindowStatus(mDisplayTracker.getDefaultDisplayId(), result.mImeToken, 425 result.mImeWindowVis, result.mImeBackDisposition, 426 result.mShowImeSwitcher); 427 } 428 } 429 buildNavBarWindows()430 private void buildNavBarWindows() { 431 mTopSystemBarWindow = mCarSystemBarController.getTopWindow(); 432 mBottomSystemBarWindow = mCarSystemBarController.getBottomWindow(); 433 mLeftSystemBarWindow = mCarSystemBarController.getLeftWindow(); 434 mRightSystemBarWindow = mCarSystemBarController.getRightWindow(); 435 436 if (mDisplayCompatToolbarController != null) { 437 if (mSystemBarConfigs 438 .isLeftDisplayCompatToolbarEnabled()) { 439 mDisplayCompatToolbarController.init(mLeftSystemBarWindow); 440 } else if (mSystemBarConfigs 441 .isRightDisplayCompatToolbarEnabled()) { 442 mDisplayCompatToolbarController.init(mRightSystemBarWindow); 443 } 444 } 445 } 446 buildNavBarContent()447 private void buildNavBarContent() { 448 mTopSystemBarView = mCarSystemBarController.getTopBar(isDeviceSetupForUser()); 449 if (mTopSystemBarView != null) { 450 mSystemBarConfigs.insetSystemBar(TOP, mTopSystemBarView); 451 mHvacController.registerHvacViews(mTopSystemBarView); 452 mTopSystemBarWindow.addView(mTopSystemBarView); 453 } 454 455 mBottomSystemBarView = mCarSystemBarController.getBottomBar(isDeviceSetupForUser()); 456 if (mBottomSystemBarView != null) { 457 mSystemBarConfigs.insetSystemBar(BOTTOM, mBottomSystemBarView); 458 mHvacController.registerHvacViews(mBottomSystemBarView); 459 mBottomSystemBarWindow.addView(mBottomSystemBarView); 460 } 461 462 mLeftSystemBarView = mCarSystemBarController.getLeftBar(isDeviceSetupForUser()); 463 if (mLeftSystemBarView != null) { 464 mSystemBarConfigs.insetSystemBar(LEFT, mLeftSystemBarView); 465 mHvacController.registerHvacViews(mLeftSystemBarView); 466 mLeftSystemBarWindow.addView(mLeftSystemBarView); 467 } 468 469 mRightSystemBarView = mCarSystemBarController.getRightBar(isDeviceSetupForUser()); 470 if (mRightSystemBarView != null) { 471 mSystemBarConfigs.insetSystemBar(RIGHT, mRightSystemBarView); 472 mHvacController.registerHvacViews(mRightSystemBarView); 473 mRightSystemBarWindow.addView(mRightSystemBarView); 474 } 475 } 476 attachNavBarWindows()477 private void attachNavBarWindows() { 478 mSystemBarConfigs.getSystemBarSidesByZOrder().forEach(this::attachNavBarBySide); 479 } 480 481 @VisibleForTesting getSystemBarWindowBySide(int side)482 ViewGroup getSystemBarWindowBySide(int side) { 483 switch (side) { 484 case TOP: 485 return mTopSystemBarWindow; 486 case BOTTOM: 487 return mBottomSystemBarWindow; 488 case LEFT: 489 return mLeftSystemBarWindow; 490 case RIGHT: 491 return mRightSystemBarWindow; 492 default: 493 return null; 494 } 495 } 496 attachNavBarBySide(int side)497 private void attachNavBarBySide(int side) { 498 switch (side) { 499 case TOP: 500 if (DEBUG) { 501 Log.d(TAG, "mTopSystemBarWindow = " + mTopSystemBarWindow 502 + ", mTopSystemBarAttached=" + mTopSystemBarAttached 503 + ", enabled=" + mSystemBarConfigs.getEnabledStatusBySide(TOP)); 504 } 505 if (mTopSystemBarWindow != null && !mTopSystemBarAttached 506 && mSystemBarConfigs.getEnabledStatusBySide(TOP)) { 507 mWindowManager.addView(mTopSystemBarWindow, 508 mSystemBarConfigs.getLayoutParamsBySide(TOP)); 509 mTopSystemBarAttached = true; 510 } 511 break; 512 case BOTTOM: 513 if (DEBUG) { 514 Log.d(TAG, "mBottomSystemBarWindow = " + mBottomSystemBarWindow 515 + ", mBottomSystemBarAttached=" + mBottomSystemBarAttached 516 + ", enabled=" + mSystemBarConfigs.getEnabledStatusBySide(BOTTOM)); 517 } 518 if (mBottomSystemBarWindow != null && !mBottomSystemBarAttached 519 && mSystemBarConfigs.getEnabledStatusBySide(BOTTOM)) { 520 mWindowManager.addView(mBottomSystemBarWindow, 521 mSystemBarConfigs.getLayoutParamsBySide(BOTTOM)); 522 mBottomSystemBarAttached = true; 523 } 524 break; 525 case LEFT: 526 if (DEBUG) { 527 Log.d(TAG, "mLeftSystemBarWindow = " + mLeftSystemBarWindow 528 + ", mLeftSystemBarAttached=" + mLeftSystemBarAttached 529 + ", enabled=" + mSystemBarConfigs.getEnabledStatusBySide(LEFT)); 530 } 531 if (mLeftSystemBarWindow != null && !mLeftSystemBarAttached 532 && mSystemBarConfigs.getEnabledStatusBySide(LEFT)) { 533 mWindowManager.addView(mLeftSystemBarWindow, 534 mSystemBarConfigs.getLayoutParamsBySide(LEFT)); 535 mLeftSystemBarAttached = true; 536 } 537 break; 538 case RIGHT: 539 if (DEBUG) { 540 Log.d(TAG, "mRightSystemBarWindow = " + mRightSystemBarWindow 541 + ", mRightSystemBarAttached=" + mRightSystemBarAttached 542 + ", " 543 + "enabled=" + mSystemBarConfigs.getEnabledStatusBySide(RIGHT)); 544 } 545 if (mRightSystemBarWindow != null && !mRightSystemBarAttached 546 && mSystemBarConfigs.getEnabledStatusBySide(RIGHT)) { 547 mWindowManager.addView(mRightSystemBarWindow, 548 mSystemBarConfigs.getLayoutParamsBySide(RIGHT)); 549 mRightSystemBarAttached = true; 550 } 551 break; 552 default: 553 return; 554 } 555 } 556 557 /** 558 * We register for soft keyboard visibility events such that we can hide the navigation bar 559 * giving more screen space to the IME. Note: this is optional and controlled by 560 * {@code com.android.internal.R.bool.config_hideNavBarForKeyboard}. 561 */ 562 @Override setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher)563 public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, 564 boolean showImeSwitcher) { 565 if (mContext.getDisplayId() != displayId) { 566 return; 567 } 568 569 boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0; 570 571 updateKeyboardVisibility(isKeyboardVisible); 572 } 573 updateKeyboardVisibility(boolean isKeyboardVisible)574 private void updateKeyboardVisibility(boolean isKeyboardVisible) { 575 if (mHideTopBarForKeyboard) { 576 mCarSystemBarController.setTopWindowVisibility( 577 isKeyboardVisible ? View.GONE : View.VISIBLE); 578 } 579 580 if (mHideBottomBarForKeyboard) { 581 mCarSystemBarController.setBottomWindowVisibility( 582 isKeyboardVisible ? View.GONE : View.VISIBLE); 583 } 584 585 if (mHideLeftBarForKeyboard) { 586 mCarSystemBarController.setLeftWindowVisibility( 587 isKeyboardVisible ? View.GONE : View.VISIBLE); 588 } 589 if (mHideRightBarForKeyboard) { 590 mCarSystemBarController.setRightWindowVisibility( 591 isKeyboardVisible ? View.GONE : View.VISIBLE); 592 } 593 } 594 595 @Override onSystemBarAttributesChanged( int displayId, @WindowInsetsController.Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, @WindowInsetsController.Behavior int behavior, @InsetsType int requestedVisibleTypes, String packageName, LetterboxDetails[] letterboxDetails)596 public void onSystemBarAttributesChanged( 597 int displayId, 598 @WindowInsetsController.Appearance int appearance, 599 AppearanceRegion[] appearanceRegions, 600 boolean navbarColorManagedByIme, 601 @WindowInsetsController.Behavior int behavior, 602 @InsetsType int requestedVisibleTypes, 603 String packageName, 604 LetterboxDetails[] letterboxDetails) { 605 if (displayId != mDisplayId) { 606 return; 607 } 608 boolean barModeChanged = updateStatusBarMode( 609 mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT); 610 int numStacks = appearanceRegions.length; 611 boolean stackAppearancesChanged = mAppearanceRegions.length != numStacks; 612 for (int i = 0; i < numStacks && !stackAppearancesChanged; i++) { 613 stackAppearancesChanged |= !appearanceRegions[i].equals(mAppearanceRegions[i]); 614 } 615 if (stackAppearancesChanged || barModeChanged) { 616 mAppearanceRegions = appearanceRegions; 617 updateStatusBarAppearance(); 618 } 619 mCarSystemBarController.refreshSystemBar(); 620 } 621 622 @Override disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2, boolean animate)623 public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2, 624 boolean animate) { 625 if (displayId != mDisplayId) { 626 return; 627 } 628 mCarSystemBarController.setSystemBarStates(state1, state2); 629 } 630 updateStatusBarAppearance()631 private void updateStatusBarAppearance() { 632 int numStacks = mAppearanceRegions.length; 633 final ArrayList<Rect> lightBarBounds = new ArrayList<>(); 634 635 for (int i = 0; i < numStacks; i++) { 636 final AppearanceRegion ar = mAppearanceRegions[i]; 637 if (isLight(ar.getAppearance())) { 638 lightBarBounds.add(ar.getBounds()); 639 } 640 } 641 642 // If all stacks are light, all icons become dark. 643 if (lightBarBounds.size() == numStacks) { 644 mStatusBarIconController.setIconsDarkArea(null); 645 mStatusBarIconController.getTransitionsController().setIconsDark( 646 /* dark= */ true, /* animate= */ false); 647 } else if (lightBarBounds.isEmpty()) { 648 // If no one is light, all icons become white. 649 mStatusBarIconController.getTransitionsController().setIconsDark( 650 /* dark= */ false, /* animate= */ false); 651 } else { 652 // Not the same for every stack, update icons in area only. 653 mStatusBarIconController.setIconsDarkArea(lightBarBounds); 654 mStatusBarIconController.getTransitionsController().setIconsDark( 655 /* dark= */ true, /* animate= */ false); 656 } 657 } 658 isLight(int appearance)659 private static boolean isLight(int appearance) { 660 return (appearance & APPEARANCE_LIGHT_STATUS_BARS) != 0; 661 } 662 663 @Override showTransient(int displayId, int types, boolean isGestureOnSystemBar)664 public void showTransient(int displayId, int types, boolean isGestureOnSystemBar) { 665 if (displayId != mDisplayId) { 666 return; 667 } 668 if ((types & WindowInsets.Type.statusBars()) != 0) { 669 if (!mStatusBarTransientShown) { 670 mStatusBarTransientShown = true; 671 handleTransientChanged(); 672 } 673 } 674 if ((types & WindowInsets.Type.navigationBars()) != 0) { 675 if (!mNavBarTransientShown) { 676 mNavBarTransientShown = true; 677 handleTransientChanged(); 678 } 679 } 680 } 681 682 @Override abortTransient(int displayId, int types)683 public void abortTransient(int displayId, int types) { 684 if (displayId != mDisplayId) { 685 return; 686 } 687 if ((types & (WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars())) == 0) { 688 return; 689 } 690 clearTransient(); 691 } 692 clearTransient()693 private void clearTransient() { 694 if (mStatusBarTransientShown) { 695 mStatusBarTransientShown = false; 696 handleTransientChanged(); 697 } 698 if (mNavBarTransientShown) { 699 mNavBarTransientShown = false; 700 handleTransientChanged(); 701 } 702 } 703 704 @VisibleForTesting isStatusBarTransientShown()705 boolean isStatusBarTransientShown() { 706 return mStatusBarTransientShown; 707 } 708 709 @VisibleForTesting isNavBarTransientShown()710 boolean isNavBarTransientShown() { 711 return mNavBarTransientShown; 712 } 713 714 @VisibleForTesting setSignalPolicy(StatusBarSignalPolicy signalPolicy)715 void setSignalPolicy(StatusBarSignalPolicy signalPolicy) { 716 mSignalPolicy = signalPolicy; 717 } 718 719 @Override dump(PrintWriter pw, String[] args)720 public void dump(PrintWriter pw, String[] args) { 721 pw.print(" mTaskStackListener="); 722 pw.println(mButtonSelectionStateListener); 723 pw.print(" mBottomSystemBarView="); 724 pw.println(mBottomSystemBarView); 725 } 726 handleTransientChanged()727 private void handleTransientChanged() { 728 updateStatusBarMode(mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT); 729 updateNavBarMode(mNavBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT); 730 } 731 732 // Returns true if the status bar mode has changed. updateStatusBarMode(int barMode)733 private boolean updateStatusBarMode(int barMode) { 734 if (mStatusBarMode != barMode) { 735 mStatusBarMode = barMode; 736 mAutoHideController.touchAutoHide(); 737 return true; 738 } 739 return false; 740 } 741 742 // Returns true if the nav bar mode has changed. updateNavBarMode(int barMode)743 private boolean updateNavBarMode(int barMode) { 744 if (mSystemBarMode != barMode) { 745 mSystemBarMode = barMode; 746 mAutoHideController.touchAutoHide(); 747 return true; 748 } 749 return false; 750 } 751 752 @Override onConfigChanged(Configuration newConfig)753 public void onConfigChanged(Configuration newConfig) { 754 Locale oldLocale = mCurrentLocale; 755 mCurrentLocale = newConfig.getLocales().get(0); 756 757 boolean isConfigNightMode = newConfig.isNightModeActive(); 758 if (isConfigNightMode == mIsUiModeNight 759 && (mCurrentLocale != null && mCurrentLocale.equals(oldLocale) 760 || mCurrentLocale == oldLocale)) { 761 return; 762 } 763 764 // Refresh UI on Night mode or system language changes. 765 if (isConfigNightMode != mIsUiModeNight) { 766 mIsUiModeNight = isConfigNightMode; 767 mUiModeManager.setNightModeActivated(mIsUiModeNight); 768 } 769 770 // cache the current state 771 // The focused view will be destroyed during re-layout, causing the framework to adjust 772 // the focus unexpectedly. To avoid that, move focus to a view that won't be 773 // destroyed during re-layout and has no focus highlight (the FocusParkingView), then 774 // move focus back to the previously focused view after re-layout. 775 mCarSystemBarController.cacheAndHideFocus(); 776 View profilePickerView = null; 777 boolean isProfilePickerOpen = false; 778 if (mTopSystemBarView != null) { 779 profilePickerView = mTopSystemBarView.findViewById(R.id.user_name); 780 } 781 if (profilePickerView != null) isProfilePickerOpen = profilePickerView.isSelected(); 782 if (isProfilePickerOpen) { 783 profilePickerView.callOnClick(); 784 } 785 786 resetSystemBarContent(/* isProvisionedStateChange= */ false); 787 788 // retrieve the previous state 789 if (isProfilePickerOpen) { 790 if (mTopSystemBarView != null) { 791 profilePickerView = mTopSystemBarView.findViewById(R.id.user_name); 792 } 793 if (profilePickerView != null) profilePickerView.callOnClick(); 794 } 795 796 mCarSystemBarController.restoreFocus(); 797 } 798 799 @VisibleForTesting restartSystemBars()800 void restartSystemBars() { 801 mCarSystemBarRestartTracker.notifyPendingRestart(/* recreateWindows= */ true, 802 /* provisionedStateChanged= */ false); 803 804 mCarSystemBarController.removeAll(); 805 mCarSystemBarController.resetSystemBarConfigs(); 806 clearSystemBarWindow(/* removeUnusedWindow= */ true); 807 buildNavBarWindows(); 808 buildNavBarContent(); 809 attachNavBarWindows(); 810 811 mCarSystemBarRestartTracker.notifyRestartComplete(/* recreateWindows= */ true, 812 /* provisionedStateChanged= */ false); 813 } 814 clearSystemBarWindow(boolean removeUnusedWindow)815 private void clearSystemBarWindow(boolean removeUnusedWindow) { 816 if (mTopSystemBarWindow != null) { 817 mTopSystemBarWindow.removeAllViews(); 818 mHvacController.unregisterViews(mTopSystemBarView); 819 if (removeUnusedWindow) { 820 mWindowManager.removeViewImmediate(mTopSystemBarWindow); 821 mTopSystemBarAttached = false; 822 } 823 mTopSystemBarView = null; 824 } 825 826 if (mBottomSystemBarWindow != null) { 827 mBottomSystemBarWindow.removeAllViews(); 828 mHvacController.unregisterViews(mBottomSystemBarView); 829 if (removeUnusedWindow) { 830 mWindowManager.removeViewImmediate(mBottomSystemBarWindow); 831 mBottomSystemBarAttached = false; 832 } 833 mBottomSystemBarView = null; 834 } 835 836 if (mLeftSystemBarWindow != null) { 837 mLeftSystemBarWindow.removeAllViews(); 838 mHvacController.unregisterViews(mLeftSystemBarView); 839 if (removeUnusedWindow) { 840 mWindowManager.removeViewImmediate(mLeftSystemBarWindow); 841 mLeftSystemBarAttached = false; 842 } 843 mLeftSystemBarView = null; 844 } 845 846 if (mRightSystemBarWindow != null) { 847 mRightSystemBarWindow.removeAllViews(); 848 mHvacController.unregisterViews(mRightSystemBarView); 849 if (removeUnusedWindow) { 850 mWindowManager.removeViewImmediate(mRightSystemBarWindow); 851 mRightSystemBarAttached = false; 852 } 853 mRightSystemBarView = null; 854 } 855 } 856 857 @VisibleForTesting setUiModeManager(UiModeManager uiModeManager)858 void setUiModeManager(UiModeManager uiModeManager) { 859 mUiModeManager = uiModeManager; 860 } 861 862 @Override onKeyboardVisibilityChanged(boolean show)863 public void onKeyboardVisibilityChanged(boolean show) { 864 updateKeyboardVisibility(show); 865 } 866 } 867