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 package com.android.systemui.car.systembar; 17 18 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 19 20 import static com.android.systemui.car.Flags.displayCompatibilityV2; 21 import static com.android.systemui.car.systembar.CarSystemBarController.BOTTOM; 22 import static com.android.systemui.car.systembar.CarSystemBarController.LEFT; 23 import static com.android.systemui.car.systembar.CarSystemBarController.RIGHT; 24 import static com.android.systemui.car.systembar.CarSystemBarController.TOP; 25 26 import android.annotation.IdRes; 27 import android.annotation.SuppressLint; 28 import android.content.Context; 29 import android.content.res.Resources; 30 import android.graphics.PixelFormat; 31 import android.os.Binder; 32 import android.util.ArrayMap; 33 import android.util.ArraySet; 34 import android.util.Log; 35 import android.view.Gravity; 36 import android.view.InsetsFrameProvider; 37 import android.view.View; 38 import android.view.ViewGroup; 39 import android.view.WindowInsets; 40 import android.view.WindowManager; 41 42 import com.android.internal.annotations.VisibleForTesting; 43 import com.android.systemui.R; 44 import com.android.systemui.car.notification.BottomNotificationPanelViewMediator; 45 import com.android.systemui.car.notification.TopNotificationPanelViewMediator; 46 import com.android.systemui.car.systembar.CarSystemBarController.SystemBarSide; 47 import com.android.systemui.dagger.qualifiers.Main; 48 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.Comparator; 52 import java.util.List; 53 import java.util.Map; 54 import java.util.Set; 55 56 import javax.inject.Inject; 57 58 /** 59 * Reads configs for system bars for each side (TOP, BOTTOM, LEFT, and RIGHT) and returns the 60 * corresponding {@link android.view.WindowManager.LayoutParams} per the configuration. 61 */ 62 public class SystemBarConfigsImpl implements SystemBarConfigs { 63 64 private static final String TAG = SystemBarConfigs.class.getSimpleName(); 65 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 66 67 // The z-order from which system bars will start to appear on top of HUN's. 68 @VisibleForTesting 69 static final int HUN_Z_ORDER = 10; 70 71 private static final Binder INSETS_OWNER = new Binder(); 72 73 /* 74 NOTE: The elements' order in the map below must be preserved as-is since the correct 75 corresponding values are obtained by the index. 76 */ 77 private static final InsetsFrameProvider[] BAR_PROVIDER_MAP = { 78 new InsetsFrameProvider( 79 INSETS_OWNER, 0 /* index */, WindowInsets.Type.statusBars()), 80 new InsetsFrameProvider( 81 INSETS_OWNER, 0 /* index */, WindowInsets.Type.navigationBars()), 82 new InsetsFrameProvider( 83 INSETS_OWNER, 1 /* index */, WindowInsets.Type.statusBars()), 84 new InsetsFrameProvider( 85 INSETS_OWNER, 1 /* index */, WindowInsets.Type.navigationBars()), 86 }; 87 88 private static final Map<@SystemBarSide Integer, Integer> BAR_GRAVITY_MAP = new ArrayMap<>(); 89 private static final Map<@SystemBarSide Integer, String> BAR_TITLE_MAP = new ArrayMap<>(); 90 private static final Map<@SystemBarSide Integer, InsetsFrameProvider> BAR_GESTURE_MAP = 91 new ArrayMap<>(); 92 93 private final Context mContext; 94 private final Resources mResources; 95 private final Map<@SystemBarSide Integer, SystemBarConfig> mSystemBarConfigMap = 96 new ArrayMap<>(); 97 private final List<@SystemBarSide Integer> mSystemBarSidesByZOrder = new ArrayList<>(); 98 /** Maps @WindowManager.LayoutParams.WindowType to window contexts for that type. */ 99 private final Map<Integer, Context> mWindowContexts = new ArrayMap<>(); 100 101 private boolean mTopNavBarEnabled; 102 private boolean mBottomNavBarEnabled; 103 private boolean mLeftNavBarEnabled; 104 private boolean mRightNavBarEnabled; 105 private int mDisplayCompatToolbarState = 0; 106 107 @Inject SystemBarConfigsImpl(Context context, @Main Resources resources)108 public SystemBarConfigsImpl(Context context, @Main Resources resources) { 109 mContext = context; 110 mResources = resources; 111 init(); 112 } 113 init()114 private void init() { 115 populateMaps(); 116 readConfigs(); 117 118 checkOnlyOneDisplayCompatIsEnabled(); 119 checkEnabledBarsHaveUniqueBarTypes(); 120 checkAllOverlappingBarsHaveDifferentZOrders(); 121 checkSystemBarEnabledForNotificationPanel(); 122 checkHideBottomBarForKeyboardConfigSync(); 123 124 setInsetPaddingsForOverlappingCorners(); 125 sortSystemBarTypesByZOrder(); 126 } 127 128 /** 129 * Invalidate cached resources and fetch from resources config file. 130 * TODO: b/260206944, Can remove this after we have a fix for overlaid resources not applied. 131 * <p> 132 * Since SystemBarConfig is a Scoped(Dagger Singleton Annotation), We will have stale values, of 133 * all the resources after the RRO is applied. 134 * Another way is to remove the Scope(Singleton), but the downside is that it will be re-created 135 * everytime. 136 * </p> 137 */ 138 @Override resetSystemBarConfigs()139 public void resetSystemBarConfigs() { 140 init(); 141 } 142 143 @Override resetSystemBarWindowContext()144 public void resetSystemBarWindowContext() { 145 for (int windowType : mWindowContexts.keySet()) { 146 Context context = mContext.createWindowContext(windowType, /* options= */ null); 147 mWindowContexts.put(windowType, context); 148 } 149 } 150 151 @Override getWindowContextBySide(@ystemBarSide int side)152 public Context getWindowContextBySide(@SystemBarSide int side) { 153 SystemBarConfig config = mSystemBarConfigMap.get(side); 154 if (config == null) { 155 return null; 156 } 157 int windowType = config.mapZOrderToBarType(config.getZOrder()); 158 if (mWindowContexts.containsKey(windowType)) { 159 return mWindowContexts.get(windowType); 160 } 161 Context context = mContext.createWindowContext(windowType, /* options= */ null); 162 mWindowContexts.put(windowType, context); 163 return context; 164 } 165 166 /** 167 * Returns the system bar layout for the given side. {@code null} if side is unknown. 168 */ 169 @Override getSystemBarLayoutBySide(@ystemBarSide int side, boolean isSetUp)170 public ViewGroup getSystemBarLayoutBySide(@SystemBarSide int side, boolean isSetUp) { 171 int layoutId = getSystemBarLayoutResBySide(side, isSetUp); 172 if (layoutId == 0) { 173 return null; 174 } 175 176 return (ViewGroup) View.inflate(getWindowContextBySide(side), layoutId, /* root= */ null); 177 } 178 getSystemBarLayoutResBySide(@ystemBarSide int side, boolean isSetUp)179 private int getSystemBarLayoutResBySide(@SystemBarSide int side, boolean isSetUp) { 180 switch (side) { 181 case LEFT: 182 if (!isSetUp) { 183 return R.layout.car_left_system_bar_unprovisioned; 184 } else { 185 return R.layout.car_left_system_bar; 186 } 187 case TOP: 188 if (!isSetUp) { 189 return R.layout.car_top_system_bar_unprovisioned; 190 } else { 191 return R.layout.car_top_system_bar; 192 } 193 case RIGHT: 194 if (!isSetUp) { 195 return R.layout.car_right_system_bar_unprovisioned; 196 } else { 197 return R.layout.car_right_system_bar; 198 } 199 case BOTTOM: 200 if (!isSetUp) { 201 return R.layout.car_bottom_system_bar_unprovisioned; 202 } else { 203 return R.layout.car_bottom_system_bar; 204 } 205 default: 206 return 0; 207 } 208 } 209 210 /** 211 * Returns the system bar window for the given side. 212 */ 213 @Override getWindowLayoutBySide(@ystemBarSide int side)214 public ViewGroup getWindowLayoutBySide(@SystemBarSide int side) { 215 int windowId = getWindowIdBySide(side); 216 if (windowId == 0) { 217 return null; 218 } 219 ViewGroup window = (ViewGroup) View.inflate(getWindowContextBySide(side), 220 R.layout.navigation_bar_window, /* root= */ null); 221 // Setting a new id to each window because we're inflating the same layout and that layout 222 // already has an id. and we don't want to have the same id on all the system bar windows. 223 window.setId(windowId); 224 return window; 225 } 226 227 /** 228 * Returns an id for the given side that can be set on the system bar window. 229 * 0 means the side is unknown. 230 */ 231 @IdRes getWindowIdBySide(@ystemBarSide int side)232 private int getWindowIdBySide(@SystemBarSide int side) { 233 return switch (side) { 234 case TOP -> R.id.car_top_bar_window; 235 case BOTTOM -> R.id.car_bottom_bar_window; 236 case LEFT -> R.id.car_left_bar_window; 237 case RIGHT -> R.id.car_right_bar_window; 238 default -> 0; 239 }; 240 } 241 242 @Override getLayoutParamsBySide(@ystemBarSide int side)243 public WindowManager.LayoutParams getLayoutParamsBySide(@SystemBarSide int side) { 244 return mSystemBarConfigMap.get(side) != null 245 ? mSystemBarConfigMap 246 .get(side).getLayoutParams() 247 : null; 248 } 249 250 @Override getEnabledStatusBySide(@ystemBarSide int side)251 public boolean getEnabledStatusBySide(@SystemBarSide int side) { 252 switch (side) { 253 case TOP: 254 return mTopNavBarEnabled; 255 case BOTTOM: 256 return mBottomNavBarEnabled; 257 case LEFT: 258 return mLeftNavBarEnabled || isLeftDisplayCompatToolbarEnabled(); 259 case RIGHT: 260 return mRightNavBarEnabled || isRightDisplayCompatToolbarEnabled(); 261 default: 262 return false; 263 } 264 } 265 266 @Override getHideForKeyboardBySide(@ystemBarSide int side)267 public boolean getHideForKeyboardBySide(@SystemBarSide int side) { 268 return mSystemBarConfigMap.get(side) != null 269 && mSystemBarConfigMap.get(side).getHideForKeyboard(); 270 } 271 272 @Override insetSystemBar(@ystemBarSide int side, ViewGroup view)273 public void insetSystemBar(@SystemBarSide int side, ViewGroup view) { 274 if (mSystemBarConfigMap.get(side) == null) return; 275 276 int[] paddings = mSystemBarConfigMap.get(side).getPaddings(); 277 if (DEBUG) { 278 Log.d(TAG, "Set padding to side = " + side + ", to " + Arrays.toString(paddings)); 279 } 280 view.setPadding(paddings[LEFT], paddings[TOP], paddings[RIGHT], paddings[BOTTOM]); 281 } 282 283 @Override getSystemBarSidesByZOrder()284 public List<@SystemBarSide Integer> getSystemBarSidesByZOrder() { 285 return mSystemBarSidesByZOrder; 286 } 287 288 @Override getSystemBarInsetTypeBySide(@ystemBarSide int side)289 public int getSystemBarInsetTypeBySide(@SystemBarSide int side) { 290 return mSystemBarConfigMap.get(side) != null 291 ? mSystemBarConfigMap.get(side).getBarType() : -1; 292 } 293 294 @Override getInsetsFrameProvider(int index)295 public InsetsFrameProvider getInsetsFrameProvider(int index) { 296 return BAR_PROVIDER_MAP[index]; 297 } 298 299 @VisibleForTesting updateInsetPaddings(@ystemBarSide int side, Map<@SystemBarSide Integer, Boolean> barVisibilities)300 void updateInsetPaddings(@SystemBarSide int side, 301 Map<@SystemBarSide Integer, Boolean> barVisibilities) { 302 SystemBarConfig currentConfig = mSystemBarConfigMap.get(side); 303 304 if (currentConfig == null) return; 305 306 int defaultLeftPadding = 0; 307 int defaultRightPadding = 0; 308 int defaultTopPadding = 0; 309 int defaultBottomPadding = 0; 310 311 switch (side) { 312 case LEFT: { 313 defaultLeftPadding = mResources 314 .getDimensionPixelSize(R.dimen.car_left_system_bar_left_padding); 315 defaultRightPadding = mResources 316 .getDimensionPixelSize(R.dimen.car_left_system_bar_right_padding); 317 defaultTopPadding = mResources 318 .getDimensionPixelSize(R.dimen.car_left_system_bar_top_padding); 319 defaultBottomPadding = mResources 320 .getDimensionPixelSize(R.dimen.car_left_system_bar_bottom_padding); 321 break; 322 } 323 case RIGHT: { 324 defaultLeftPadding = mResources 325 .getDimensionPixelSize(R.dimen.car_right_system_bar_left_padding); 326 defaultRightPadding = mResources 327 .getDimensionPixelSize(R.dimen.car_right_system_bar_right_padding); 328 defaultTopPadding = mResources 329 .getDimensionPixelSize(R.dimen.car_right_system_bar_top_padding); 330 defaultBottomPadding = mResources 331 .getDimensionPixelSize(R.dimen.car_right_system_bar_bottom_padding); 332 break; 333 } 334 case TOP: { 335 defaultLeftPadding = mResources 336 .getDimensionPixelSize(R.dimen.car_top_system_bar_left_padding); 337 defaultRightPadding = mResources 338 .getDimensionPixelSize(R.dimen.car_top_system_bar_right_padding); 339 defaultTopPadding = mResources 340 .getDimensionPixelSize(R.dimen.car_top_system_bar_top_padding); 341 defaultBottomPadding = mResources 342 .getDimensionPixelSize(R.dimen.car_top_system_bar_bottom_padding); 343 break; 344 } 345 case BOTTOM: { 346 defaultLeftPadding = mResources 347 .getDimensionPixelSize(R.dimen.car_bottom_system_bar_left_padding); 348 defaultRightPadding = mResources 349 .getDimensionPixelSize(R.dimen.car_bottom_system_bar_right_padding); 350 defaultTopPadding = mResources 351 .getDimensionPixelSize(R.dimen.car_bottom_system_bar_top_padding); 352 defaultBottomPadding = mResources 353 .getDimensionPixelSize(R.dimen.car_bottom_system_bar_bottom_padding); 354 break; 355 } 356 default: 357 } 358 359 currentConfig.setPaddingBySide(LEFT, defaultLeftPadding); 360 currentConfig.setPaddingBySide(RIGHT, defaultRightPadding); 361 currentConfig.setPaddingBySide(TOP, defaultTopPadding); 362 currentConfig.setPaddingBySide(BOTTOM, defaultBottomPadding); 363 364 if (isHorizontalBar(side)) { 365 if (mLeftNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get( 366 LEFT).getZOrder()) { 367 currentConfig.setPaddingBySide(LEFT, 368 barVisibilities.get(LEFT) 369 ? mSystemBarConfigMap.get(LEFT).getGirth() 370 : defaultLeftPadding); 371 } 372 if (mRightNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get( 373 RIGHT).getZOrder()) { 374 currentConfig.setPaddingBySide(RIGHT, 375 barVisibilities.get(RIGHT) 376 ? mSystemBarConfigMap.get(RIGHT).getGirth() 377 : defaultRightPadding); 378 } 379 } 380 if (isVerticalBar(side)) { 381 if (mTopNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get( 382 TOP).getZOrder()) { 383 currentConfig.setPaddingBySide(TOP, 384 barVisibilities.get(TOP) 385 ? mSystemBarConfigMap.get(TOP).getGirth() 386 : defaultTopPadding); 387 } 388 if (mBottomNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get( 389 BOTTOM).getZOrder()) { 390 currentConfig.setPaddingBySide(BOTTOM, 391 barVisibilities.get(BOTTOM) 392 ? mSystemBarConfigMap.get(BOTTOM).getGirth() 393 : defaultBottomPadding); 394 } 395 396 } 397 if (DEBUG) { 398 Log.d(TAG, "Update padding for side = " + side + " to " 399 + Arrays.toString(currentConfig.getPaddings())); 400 } 401 } 402 403 @SuppressLint("RtlHardcoded") populateMaps()404 private static void populateMaps() { 405 BAR_GRAVITY_MAP.put(TOP, Gravity.TOP); 406 BAR_GRAVITY_MAP.put(BOTTOM, Gravity.BOTTOM); 407 BAR_GRAVITY_MAP.put(LEFT, Gravity.LEFT); 408 BAR_GRAVITY_MAP.put(RIGHT, Gravity.RIGHT); 409 410 BAR_TITLE_MAP.put(TOP, "TopCarSystemBar"); 411 BAR_TITLE_MAP.put(BOTTOM, "BottomCarSystemBar"); 412 BAR_TITLE_MAP.put(LEFT, "LeftCarSystemBar"); 413 BAR_TITLE_MAP.put(RIGHT, "RightCarSystemBar"); 414 415 BAR_GESTURE_MAP.put(TOP, new InsetsFrameProvider( 416 INSETS_OWNER, 0 /* index */, WindowInsets.Type.mandatorySystemGestures())); 417 BAR_GESTURE_MAP.put(BOTTOM, new InsetsFrameProvider( 418 INSETS_OWNER, 1 /* index */, WindowInsets.Type.mandatorySystemGestures())); 419 BAR_GESTURE_MAP.put(LEFT, new InsetsFrameProvider( 420 INSETS_OWNER, 2 /* index */, WindowInsets.Type.mandatorySystemGestures())); 421 BAR_GESTURE_MAP.put(RIGHT, new InsetsFrameProvider( 422 INSETS_OWNER, 3 /* index */, WindowInsets.Type.mandatorySystemGestures())); 423 } 424 readConfigs()425 private void readConfigs() { 426 mTopNavBarEnabled = mResources.getBoolean(R.bool.config_enableTopSystemBar); 427 mBottomNavBarEnabled = mResources.getBoolean(R.bool.config_enableBottomSystemBar); 428 mLeftNavBarEnabled = mResources.getBoolean(R.bool.config_enableLeftSystemBar); 429 mRightNavBarEnabled = mResources.getBoolean(R.bool.config_enableRightSystemBar); 430 mDisplayCompatToolbarState = 431 mResources.getInteger(R.integer.config_showDisplayCompatToolbarOnSystemBar); 432 mSystemBarConfigMap.clear(); 433 434 if ((mLeftNavBarEnabled && isLeftDisplayCompatToolbarEnabled()) 435 || (mRightNavBarEnabled && isRightDisplayCompatToolbarEnabled())) { 436 throw new IllegalStateException( 437 "Navigation Bar and Display Compat toolbar can't be " 438 + "on the same side"); 439 } 440 441 if (mTopNavBarEnabled) { 442 SystemBarConfig topBarConfig = 443 new SystemBarConfigBuilder() 444 .setSide(TOP) 445 .setGirth(mResources.getDimensionPixelSize( 446 R.dimen.car_top_system_bar_height)) 447 .setBarType( 448 mResources.getInteger(R.integer.config_topSystemBarType)) 449 .setZOrder( 450 mResources.getInteger(R.integer.config_topSystemBarZOrder)) 451 .setHideForKeyboard(mResources.getBoolean( 452 R.bool.config_hideTopSystemBarForKeyboard)) 453 .build(); 454 mSystemBarConfigMap.put(TOP, topBarConfig); 455 } 456 457 if (mBottomNavBarEnabled) { 458 SystemBarConfig bottomBarConfig = 459 new SystemBarConfigBuilder() 460 .setSide(BOTTOM) 461 .setGirth(mResources.getDimensionPixelSize( 462 R.dimen.car_bottom_system_bar_height)) 463 .setBarType( 464 mResources.getInteger(R.integer.config_bottomSystemBarType)) 465 .setZOrder( 466 mResources.getInteger( 467 R.integer.config_bottomSystemBarZOrder)) 468 .setHideForKeyboard(mResources.getBoolean( 469 R.bool.config_hideBottomSystemBarForKeyboard)) 470 .build(); 471 mSystemBarConfigMap.put(BOTTOM, bottomBarConfig); 472 } 473 474 if (mLeftNavBarEnabled || isLeftDisplayCompatToolbarEnabled()) { 475 SystemBarConfig leftBarConfig = 476 new SystemBarConfigBuilder() 477 .setSide(LEFT) 478 .setGirth(mResources.getDimensionPixelSize( 479 R.dimen.car_left_system_bar_width)) 480 .setBarType( 481 mResources.getInteger(R.integer.config_leftSystemBarType)) 482 .setZOrder( 483 mResources.getInteger(R.integer.config_leftSystemBarZOrder)) 484 .setHideForKeyboard(mResources.getBoolean( 485 R.bool.config_hideLeftSystemBarForKeyboard)) 486 .build(); 487 mSystemBarConfigMap.put(LEFT, leftBarConfig); 488 } 489 490 if (mRightNavBarEnabled || isRightDisplayCompatToolbarEnabled()) { 491 SystemBarConfig rightBarConfig = 492 new SystemBarConfigBuilder() 493 .setSide(RIGHT) 494 .setGirth(mResources.getDimensionPixelSize( 495 R.dimen.car_right_system_bar_width)) 496 .setBarType( 497 mResources.getInteger(R.integer.config_rightSystemBarType)) 498 .setZOrder(mResources.getInteger( 499 R.integer.config_rightSystemBarZOrder)) 500 .setHideForKeyboard(mResources.getBoolean( 501 R.bool.config_hideRightSystemBarForKeyboard)) 502 .build(); 503 mSystemBarConfigMap.put(RIGHT, rightBarConfig); 504 } 505 } 506 checkOnlyOneDisplayCompatIsEnabled()507 private void checkOnlyOneDisplayCompatIsEnabled() throws IllegalStateException { 508 boolean useRemoteLaunchTaskView = 509 mResources.getBoolean(R.bool.config_useRemoteLaunchTaskView); 510 int displayCompatEnabled = 511 mResources.getInteger(R.integer.config_showDisplayCompatToolbarOnSystemBar); 512 if (useRemoteLaunchTaskView && displayCompatEnabled != 0) { 513 throw new IllegalStateException("config_useRemoteLaunchTaskView is enabled but " 514 + "config_showDisplayCompatToolbarOnSystemBar is non-zero"); 515 } 516 } 517 checkEnabledBarsHaveUniqueBarTypes()518 private void checkEnabledBarsHaveUniqueBarTypes() throws RuntimeException { 519 Set<Integer> barTypesUsed = new ArraySet<>(); 520 int enabledNavBarCount = mSystemBarConfigMap.size(); 521 522 for (SystemBarConfig systemBarConfig : mSystemBarConfigMap.values()) { 523 barTypesUsed.add(systemBarConfig.getBarType()); 524 } 525 526 // The number of bar types used cannot be fewer than that of enabled system bars. 527 if (barTypesUsed.size() < enabledNavBarCount) { 528 throw new RuntimeException("Each enabled system bar must have a unique bar type. Check " 529 + "the configuration in config.xml"); 530 } 531 } 532 checkAllOverlappingBarsHaveDifferentZOrders()533 private void checkAllOverlappingBarsHaveDifferentZOrders() { 534 checkOverlappingBarsHaveDifferentZOrders(TOP, LEFT); 535 checkOverlappingBarsHaveDifferentZOrders(TOP, RIGHT); 536 checkOverlappingBarsHaveDifferentZOrders(BOTTOM, LEFT); 537 checkOverlappingBarsHaveDifferentZOrders(BOTTOM, RIGHT); 538 } 539 checkSystemBarEnabledForNotificationPanel()540 private void checkSystemBarEnabledForNotificationPanel() throws RuntimeException { 541 String notificationPanelMediatorName = 542 mResources.getString(R.string.config_notificationPanelViewMediator); 543 if (notificationPanelMediatorName == null) { 544 return; 545 } 546 547 Class<?> notificationPanelMediatorUsed = null; 548 try { 549 notificationPanelMediatorUsed = Class.forName(notificationPanelMediatorName); 550 } catch (ClassNotFoundException e) { 551 Log.e(TAG, "notification panel mediator class not found", e); 552 } 553 554 if (!mTopNavBarEnabled && TopNotificationPanelViewMediator.class.isAssignableFrom( 555 notificationPanelMediatorUsed)) { 556 throw new RuntimeException( 557 "Top System Bar must be enabled to use " + notificationPanelMediatorName); 558 } 559 560 if (!mBottomNavBarEnabled && BottomNotificationPanelViewMediator.class.isAssignableFrom( 561 notificationPanelMediatorUsed)) { 562 throw new RuntimeException("Bottom System Bar must be enabled to use " 563 + notificationPanelMediatorName); 564 } 565 } 566 checkHideBottomBarForKeyboardConfigSync()567 private void checkHideBottomBarForKeyboardConfigSync() throws RuntimeException { 568 if (mBottomNavBarEnabled) { 569 boolean actual = mResources.getBoolean(R.bool.config_hideBottomSystemBarForKeyboard); 570 boolean expected = mResources.getBoolean( 571 com.android.internal.R.bool.config_hideNavBarForKeyboard); 572 573 if (actual != expected) { 574 throw new RuntimeException("config_hideBottomSystemBarForKeyboard must not be " 575 + "overlaid directly and should always refer to" 576 + "config_hideNavBarForKeyboard. However, their values " 577 + "currently do not sync. Set config_hideBottomSystemBarForKeyguard to " 578 + "@*android:bool/config_hideNavBarForKeyboard. To change its " 579 + "value, overlay config_hideNavBarForKeyboard in " 580 + "framework/base/core/res/res."); 581 } 582 } 583 } 584 setInsetPaddingsForOverlappingCorners()585 private void setInsetPaddingsForOverlappingCorners() { 586 Map<@SystemBarSide Integer, Boolean> systemBarVisibilityOnInit = 587 getSystemBarsVisibilityOnInit(); 588 updateInsetPaddings(TOP, systemBarVisibilityOnInit); 589 updateInsetPaddings(BOTTOM, systemBarVisibilityOnInit); 590 updateInsetPaddings(LEFT, systemBarVisibilityOnInit); 591 updateInsetPaddings(RIGHT, systemBarVisibilityOnInit); 592 } 593 sortSystemBarTypesByZOrder()594 private void sortSystemBarTypesByZOrder() { 595 List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values()); 596 597 systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() { 598 @Override 599 public int compare(SystemBarConfig o1, SystemBarConfig o2) { 600 return o1.getZOrder() - o2.getZOrder(); 601 } 602 }); 603 604 mSystemBarSidesByZOrder.clear(); 605 systemBarsByZOrder.forEach(systemBarConfig -> { 606 mSystemBarSidesByZOrder.add(systemBarConfig.getSide()); 607 }); 608 } 609 610 // On init, system bars are visible as long as they are enabled. getSystemBarsVisibilityOnInit()611 private Map<@SystemBarSide Integer, Boolean> getSystemBarsVisibilityOnInit() { 612 ArrayMap<@SystemBarSide Integer, Boolean> visibilityMap = new ArrayMap<>(); 613 visibilityMap.put(TOP, mTopNavBarEnabled); 614 visibilityMap.put(BOTTOM, mBottomNavBarEnabled); 615 visibilityMap.put(LEFT, mLeftNavBarEnabled || isLeftDisplayCompatToolbarEnabled()); 616 visibilityMap.put(RIGHT, mRightNavBarEnabled || isRightDisplayCompatToolbarEnabled()); 617 return visibilityMap; 618 } 619 checkOverlappingBarsHaveDifferentZOrders(@ystemBarSide int horizontalSide, @SystemBarSide int verticalSide)620 private void checkOverlappingBarsHaveDifferentZOrders(@SystemBarSide int horizontalSide, 621 @SystemBarSide int verticalSide) { 622 623 if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) { 624 Log.w(TAG, "configureBarPaddings: Returning immediately since the horizontal and " 625 + "vertical sides were not provided correctly."); 626 return; 627 } 628 629 SystemBarConfig horizontalBarConfig = mSystemBarConfigMap.get(horizontalSide); 630 SystemBarConfig verticalBarConfig = mSystemBarConfigMap.get(verticalSide); 631 632 if (verticalBarConfig != null && horizontalBarConfig != null) { 633 int horizontalBarZOrder = horizontalBarConfig.getZOrder(); 634 int verticalBarZOrder = verticalBarConfig.getZOrder(); 635 636 if (horizontalBarZOrder == verticalBarZOrder) { 637 throw new RuntimeException( 638 BAR_TITLE_MAP.get(horizontalSide) + " " + BAR_TITLE_MAP.get(verticalSide) 639 + " have the same Z-Order, and so their placing order cannot be " 640 + "determined. Determine which bar should be placed on top of the " 641 + "other bar and change the Z-order in config.xml accordingly." 642 ); 643 } 644 } 645 } 646 isHorizontalBar(@ystemBarSide int side)647 private static boolean isHorizontalBar(@SystemBarSide int side) { 648 return side == TOP || side == BOTTOM; 649 } 650 isVerticalBar(@ystemBarSide int side)651 private static boolean isVerticalBar(@SystemBarSide int side) { 652 return side == LEFT || side == RIGHT; 653 } 654 655 @Override isLeftDisplayCompatToolbarEnabled()656 public boolean isLeftDisplayCompatToolbarEnabled() { 657 return displayCompatibilityV2() && mDisplayCompatToolbarState == 1; 658 } 659 660 @Override isRightDisplayCompatToolbarEnabled()661 public boolean isRightDisplayCompatToolbarEnabled() { 662 return displayCompatibilityV2() && mDisplayCompatToolbarState == 2; 663 } 664 665 private static final class SystemBarConfig { 666 private final int mSide; 667 private final int mBarType; 668 private final int mGirth; 669 private final int mZOrder; 670 private final boolean mHideForKeyboard; 671 672 private int[] mPaddings = new int[]{0, 0, 0, 0}; 673 SystemBarConfig(@ystemBarSide int side, int barType, int girth, int zOrder, boolean hideForKeyboard)674 private SystemBarConfig(@SystemBarSide int side, int barType, int girth, int zOrder, 675 boolean hideForKeyboard) { 676 mSide = side; 677 mBarType = barType; 678 mGirth = girth; 679 mZOrder = zOrder; 680 mHideForKeyboard = hideForKeyboard; 681 } 682 getSide()683 private int getSide() { 684 return mSide; 685 } 686 getBarType()687 private int getBarType() { 688 return mBarType; 689 } 690 getGirth()691 private int getGirth() { 692 return mGirth; 693 } 694 getZOrder()695 private int getZOrder() { 696 return mZOrder; 697 } 698 getHideForKeyboard()699 private boolean getHideForKeyboard() { 700 return mHideForKeyboard; 701 } 702 getPaddings()703 private int[] getPaddings() { 704 return mPaddings; 705 } 706 getLayoutParams()707 private WindowManager.LayoutParams getLayoutParams() { 708 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 709 isHorizontalBar(mSide) ? ViewGroup.LayoutParams.MATCH_PARENT : mGirth, 710 isHorizontalBar(mSide) ? mGirth : ViewGroup.LayoutParams.MATCH_PARENT, 711 mapZOrderToBarType(mZOrder), 712 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 713 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 714 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH 715 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 716 PixelFormat.TRANSLUCENT); 717 lp.setTitle(BAR_TITLE_MAP.get(mSide)); 718 lp.providedInsets = new InsetsFrameProvider[]{ 719 BAR_PROVIDER_MAP[mBarType], 720 BAR_GESTURE_MAP.get(mSide) 721 }; 722 lp.setFitInsetsTypes(0); 723 lp.windowAnimations = 0; 724 lp.gravity = BAR_GRAVITY_MAP.get(mSide); 725 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 726 lp.privateFlags = lp.privateFlags 727 | WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; 728 return lp; 729 } 730 mapZOrderToBarType(int zOrder)731 private int mapZOrderToBarType(int zOrder) { 732 return zOrder >= HUN_Z_ORDER ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL 733 : WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; 734 } 735 setPaddingBySide(@ystemBarSide int side, int padding)736 private void setPaddingBySide(@SystemBarSide int side, int padding) { 737 mPaddings[side] = padding; 738 } 739 } 740 741 private static final class SystemBarConfigBuilder { 742 private int mSide; 743 private int mBarType; 744 private int mGirth; 745 private int mZOrder; 746 private boolean mHideForKeyboard; 747 setSide(@ystemBarSide int side)748 private SystemBarConfigBuilder setSide(@SystemBarSide int side) { 749 mSide = side; 750 return this; 751 } 752 setBarType(int type)753 private SystemBarConfigBuilder setBarType(int type) { 754 mBarType = type; 755 return this; 756 } 757 setGirth(int girth)758 private SystemBarConfigBuilder setGirth(int girth) { 759 mGirth = girth; 760 return this; 761 } 762 setZOrder(int zOrder)763 private SystemBarConfigBuilder setZOrder(int zOrder) { 764 mZOrder = zOrder; 765 return this; 766 } 767 setHideForKeyboard(boolean hide)768 private SystemBarConfigBuilder setHideForKeyboard(boolean hide) { 769 mHideForKeyboard = hide; 770 return this; 771 } 772 build()773 private SystemBarConfig build() { 774 return new SystemBarConfig(mSide, mBarType, mGirth, mZOrder, mHideForKeyboard); 775 } 776 } 777 } 778