1 /* 2 * Copyright (C) 2015 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.layoutlib.bridge.impl; 18 19 import com.android.ide.common.rendering.api.HardwareConfig; 20 import com.android.ide.common.rendering.api.RenderResources; 21 import com.android.ide.common.rendering.api.ResourceNamespace; 22 import com.android.ide.common.rendering.api.ResourceReference; 23 import com.android.ide.common.rendering.api.ResourceValue; 24 import com.android.ide.common.rendering.api.SessionParams; 25 import com.android.layoutlib.bridge.Bridge; 26 import com.android.layoutlib.bridge.android.BridgeContext; 27 import com.android.layoutlib.bridge.android.RenderParamsFlags; 28 import com.android.layoutlib.bridge.bars.AppCompatActionBar; 29 import com.android.layoutlib.bridge.bars.BridgeActionBar; 30 import com.android.layoutlib.bridge.bars.Config; 31 import com.android.layoutlib.bridge.bars.FrameworkActionBar; 32 import com.android.layoutlib.bridge.bars.NavigationBar; 33 import com.android.layoutlib.bridge.bars.StatusBar; 34 import com.android.layoutlib.bridge.bars.TitleBar; 35 import com.android.resources.Density; 36 import com.android.resources.ResourceType; 37 import com.android.resources.ScreenOrientation; 38 39 import android.annotation.NonNull; 40 import android.annotation.Nullable; 41 import android.graphics.Color; 42 import android.graphics.drawable.Drawable; 43 import android.util.DisplayMetrics; 44 import android.util.TypedValue; 45 import android.view.AttachInfo_Accessor; 46 import android.view.View; 47 import android.view.ViewRootImpl; 48 import android.view.ViewRootImpl_Accessor; 49 import android.widget.FrameLayout; 50 import android.widget.LinearLayout; 51 import android.widget.RelativeLayout; 52 53 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 54 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 55 import static android.widget.LinearLayout.VERTICAL; 56 import static com.android.layoutlib.bridge.impl.ResourceHelper.getBooleanThemeFrameworkAttrValue; 57 import static com.android.layoutlib.bridge.impl.ResourceHelper.getBooleanThemeValue; 58 59 /** 60 * The Layout used to create the system decor. 61 * <p> 62 * The layout inflated will contain a content frame where the user's layout can be inflated. 63 * <pre> 64 * +-------------------------------------------------+---+ 65 * | Status bar | N | 66 * +-------------------------------------------------+ a | 67 * | Title/Framework Action bar (optional) | v | 68 * +-------------------------------------------------+ | 69 * | AppCompat Action bar (optional) | | 70 * +-------------------------------------------------+ | 71 * | Content, vertical extending | b | 72 * | | a | 73 * | | r | 74 * +-------------------------------------------------+---+ 75 * </pre> 76 * or 77 * <pre> 78 * +--------------------------------------+ 79 * | Status bar | 80 * +--------------------------------------+ 81 * | Title/Framework Action bar (optional)| 82 * +--------------------------------------+ 83 * | AppCompat Action bar (optional) | 84 * +--------------------------------------+ 85 * | Content, vertical extending | 86 * | | 87 * | | 88 * +--------------------------------------+ 89 * | Nav bar | 90 * +--------------------------------------+ 91 * </pre> 92 */ 93 class Layout extends FrameLayout { 94 95 // Theme attributes used for configuring appearance of the system decor. 96 private static final String ATTR_WINDOW_FLOATING = "windowIsFloating"; 97 private static final String ATTR_WINDOW_BACKGROUND = "windowBackground"; 98 private static final String ATTR_WINDOW_FULL_SCREEN = "windowFullscreen"; 99 private static final String ATTR_NAV_BAR_HEIGHT = "navigation_bar_height"; 100 private static final String ATTR_NAV_BAR_WIDTH = "navigation_bar_width"; 101 private static final String ATTR_STATUS_BAR_HEIGHT = "status_bar_height"; 102 private static final String ATTR_WINDOW_ACTION_BAR = "windowActionBar"; 103 private static final String ATTR_ACTION_BAR_SIZE = "actionBarSize"; 104 private static final String ATTR_WINDOW_NO_TITLE = "windowNoTitle"; 105 private static final String ATTR_WINDOW_TITLE_SIZE = "windowTitleSize"; 106 private static final String ATTR_WINDOW_TRANSLUCENT_STATUS = StatusBar.ATTR_TRANSLUCENT; 107 private static final String ATTR_WINDOW_TRANSLUCENT_NAV = NavigationBar.ATTR_TRANSLUCENT; 108 109 // Default sizes 110 private static final int DEFAULT_STATUS_BAR_HEIGHT = 25; 111 private static final int DEFAULT_TITLE_BAR_HEIGHT = 25; 112 private static final int DEFAULT_NAV_BAR_SIZE = 48; 113 114 // Ids assigned to components created. This is so that we can refer to other components in 115 // layout params. 116 private static final String ID_NAV_BAR = "navBar"; 117 private static final String ID_STATUS_BAR = "statusBar"; 118 private static final String ID_APP_COMPAT_ACTION_BAR = "appCompatActionBar"; 119 private static final String ID_FRAMEWORK_BAR = "frameworkBar"; 120 // Prefix used with the above ids in order to make them unique in framework namespace. 121 private static final String ID_PREFIX = "android_layoutlib_"; 122 123 /** 124 * Temporarily store the builder so that it doesn't have to be passed to all methods used 125 * during inflation. 126 */ 127 private Builder mBuilder; 128 129 /** 130 * SysUI layout 131 */ 132 private RelativeLayout mSysUiRoot; 133 134 /** 135 * This holds user's layout. 136 */ 137 private FrameLayout mContentRoot; 138 Layout(@onNull Builder builder)139 public Layout(@NonNull Builder builder) { 140 super(builder.mContext); 141 142 mBuilder = builder; 143 View frameworkActionBar = null; 144 View appCompatActionBar = null; 145 TitleBar titleBar = null; 146 StatusBar statusBar = null; 147 NavigationBar navBar = null; 148 149 if (builder.mWindowBackground != null) { 150 Drawable d = ResourceHelper.getDrawable(builder.mWindowBackground, builder.mContext); 151 setBackground(d); 152 } 153 154 int simulatedPlatformVersion = getParams().getSimulatedPlatformVersion(); 155 HardwareConfig hwConfig = getParams().getHardwareConfig(); 156 Density density = hwConfig.getDensity(); 157 boolean isRtl = Bridge.isLocaleRtl(getParams().getLocale()); 158 setLayoutDirection(isRtl ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR); 159 160 if (mBuilder.hasNavBar()) { 161 navBar = createNavBar(getContext(), density, isRtl, getParams().isRtlSupported(), 162 simulatedPlatformVersion, false); 163 } 164 165 if (builder.hasStatusBar()) { 166 statusBar = createStatusBar(getContext(), density, isRtl, getParams().isRtlSupported(), 167 simulatedPlatformVersion); 168 } 169 170 if (mBuilder.hasAppCompatActionBar()) { 171 BridgeActionBar bar = createActionBar(getContext(), getParams(), true); 172 mContentRoot = bar.getContentRoot(); 173 appCompatActionBar = bar.getRootView(); 174 } 175 176 // Title bar must appear on top of the Action bar 177 if (mBuilder.hasTitleBar()) { 178 titleBar = createTitleBar(getContext(), getParams().getAppLabel(), 179 simulatedPlatformVersion); 180 } else if (mBuilder.hasFrameworkActionBar()) { 181 BridgeActionBar bar = createActionBar(getContext(), getParams(), false); 182 if(mContentRoot == null) { 183 // We only set the content root if the AppCompat action bar did not already 184 // provide it 185 mContentRoot = bar.getContentRoot(); 186 } 187 frameworkActionBar = bar.getRootView(); 188 } 189 190 mSysUiRoot = new RelativeLayout(builder.mContext); 191 addSystemUiViews(titleBar, mContentRoot == null ? (mContentRoot = createContentFrame()) : frameworkActionBar, 192 statusBar, navBar, appCompatActionBar); 193 addView(mSysUiRoot); 194 //addView(createSysUiOverlay(mBuilder.mContext)); 195 // Done with the builder. Don't hold a reference to it. 196 mBuilder = null; 197 } 198 199 @NonNull createSysUiOverlay(@onNull BridgeContext context)200 private static View createSysUiOverlay(@NonNull BridgeContext context) { 201 SysUiOverlay overlay = new SysUiOverlay(context, 20, 10, 50, 40, 60); 202 overlay.setNotchColor(Color.BLACK); 203 overlay.setLayoutParams(new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 204 return overlay; 205 } 206 207 @NonNull createContentFrame()208 private FrameLayout createContentFrame() { 209 FrameLayout contentRoot = new FrameLayout(getContext()); 210 RelativeLayout.LayoutParams params = createSysUiLayoutParams(MATCH_PARENT, MATCH_PARENT); 211 int rule = mBuilder.isNavBarVertical() ? RelativeLayout.START_OF : RelativeLayout.ABOVE; 212 if (mBuilder.hasSolidNavBar()) { 213 params.addRule(rule, getId(ID_NAV_BAR)); 214 } 215 int below = -1; 216 if (mBuilder.mAppCompatActionBarSize > 0) { 217 below = getId(ID_APP_COMPAT_ACTION_BAR); 218 } else if (mBuilder.hasFrameworkActionBar() || mBuilder.hasTitleBar()) { 219 below = getId(ID_FRAMEWORK_BAR); 220 } else if (mBuilder.hasSolidStatusBar()) { 221 below = getId(ID_STATUS_BAR); 222 } 223 if (below != -1) { 224 params.addRule(RelativeLayout.BELOW, below); 225 } 226 contentRoot.setLayoutParams(params); 227 return contentRoot; 228 } 229 230 @NonNull createSysUiLayoutParams(int width, int height)231 private RelativeLayout.LayoutParams createSysUiLayoutParams(int width, int height) { 232 DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); 233 if (width > 0) { 234 width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics); 235 } 236 if (height > 0) { 237 height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics); 238 } 239 return new RelativeLayout.LayoutParams(width, height); 240 } 241 242 @NonNull getContentRoot()243 public FrameLayout getContentRoot() { 244 return mContentRoot; 245 } 246 247 @NonNull getParams()248 private SessionParams getParams() { 249 return mBuilder.mParams; 250 } 251 252 @NonNull 253 @Override getContext()254 public BridgeContext getContext() { 255 return (BridgeContext) super.getContext(); 256 } 257 258 /** 259 * @param isRtl whether the current locale is an RTL locale. 260 * @param isRtlSupported whether the applications supports RTL (i.e. has supportsRtl=true in the 261 * manifest and targetSdkVersion >= 17. 262 */ 263 @NonNull createStatusBar(BridgeContext context, Density density, boolean isRtl, boolean isRtlSupported, int simulatedPlatformVersion)264 private StatusBar createStatusBar(BridgeContext context, Density density, boolean isRtl, 265 boolean isRtlSupported, int simulatedPlatformVersion) { 266 StatusBar statusBar = 267 new StatusBar(context, density, isRtl, isRtlSupported, simulatedPlatformVersion); 268 RelativeLayout.LayoutParams params = createSysUiLayoutParams(MATCH_PARENT, mBuilder 269 .mStatusBarSize); 270 if (mBuilder.isNavBarVertical()) { 271 params.addRule(RelativeLayout.START_OF, getId(ID_NAV_BAR)); 272 } 273 statusBar.setLayoutParams(params); 274 statusBar.setId(getId(ID_STATUS_BAR)); 275 return statusBar; 276 } 277 createActionBar(@onNull BridgeContext context, @NonNull SessionParams params, boolean appCompatActionBar)278 private BridgeActionBar createActionBar(@NonNull BridgeContext context, 279 @NonNull SessionParams params, boolean appCompatActionBar) { 280 boolean isMenu = "menu".equals(params.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG)); 281 String id; 282 283 // For the framework action bar, we set the height to MATCH_PARENT only if there is no 284 // AppCompat ActionBar below it 285 int heightRule = appCompatActionBar || !mBuilder.hasAppCompatActionBar() ? MATCH_PARENT : 286 WRAP_CONTENT; 287 RelativeLayout.LayoutParams layoutParams = createSysUiLayoutParams(MATCH_PARENT, heightRule); 288 int rule = mBuilder.isNavBarVertical() ? RelativeLayout.START_OF : RelativeLayout.ABOVE; 289 if (mBuilder.hasSolidNavBar()) { 290 // If there 291 if(rule == RelativeLayout.START_OF || appCompatActionBar || !mBuilder.hasAppCompatActionBar()) { 292 layoutParams.addRule(rule, getId(ID_NAV_BAR)); 293 } 294 } 295 296 297 BridgeActionBar actionBar; 298 if (appCompatActionBar && !isMenu) { 299 actionBar = new AppCompatActionBar(context, params); 300 id = ID_APP_COMPAT_ACTION_BAR; 301 302 if (mBuilder.hasTitleBar() || mBuilder.hasFrameworkActionBar()) { 303 layoutParams.addRule(RelativeLayout.BELOW, getId(ID_FRAMEWORK_BAR)); 304 } else if (mBuilder.hasSolidStatusBar()) { 305 layoutParams.addRule(RelativeLayout.BELOW, getId(ID_STATUS_BAR)); 306 } 307 } else { 308 actionBar = new FrameworkActionBar(context, params); 309 id = ID_FRAMEWORK_BAR; 310 if (mBuilder.hasSolidStatusBar()) { 311 layoutParams.addRule(RelativeLayout.BELOW, getId(ID_STATUS_BAR)); 312 } 313 } 314 315 actionBar.getRootView().setLayoutParams(layoutParams); 316 actionBar.getRootView().setId(getId(id)); 317 actionBar.createMenuPopup(); 318 return actionBar; 319 } 320 321 @NonNull createTitleBar(BridgeContext context, String title, int simulatedPlatformVersion)322 private TitleBar createTitleBar(BridgeContext context, String title, 323 int simulatedPlatformVersion) { 324 TitleBar titleBar = new TitleBar(context, title, simulatedPlatformVersion); 325 RelativeLayout.LayoutParams params = createSysUiLayoutParams(MATCH_PARENT, mBuilder.mTitleBarSize); 326 if (mBuilder.hasSolidStatusBar()) { 327 params.addRule(RelativeLayout.BELOW, getId(ID_STATUS_BAR)); 328 } 329 if (mBuilder.isNavBarVertical() && mBuilder.hasSolidNavBar()) { 330 params.addRule(RelativeLayout.START_OF, getId(ID_NAV_BAR)); 331 } 332 titleBar.setLayoutParams(params); 333 titleBar.setId(getId(ID_FRAMEWORK_BAR)); 334 return titleBar; 335 } 336 337 /** 338 * @param isRtl whether the current locale is an RTL locale. 339 * @param isRtlSupported whether the applications supports RTL (i.e. has supportsRtl=true in the 340 * manifest and targetSdkVersion >= 17. 341 */ 342 @NonNull createNavBar(BridgeContext context, Density density, boolean isRtl, boolean isRtlSupported, int simulatedPlatformVersion, boolean isQuickStepEnabled)343 private NavigationBar createNavBar(BridgeContext context, Density density, boolean isRtl, 344 boolean isRtlSupported, int simulatedPlatformVersion, boolean isQuickStepEnabled) { 345 int orientation = mBuilder.mNavBarOrientation; 346 int size = mBuilder.mNavBarSize; 347 // Only allow quickstep in the latest version or >= 28 348 isQuickStepEnabled = isQuickStepEnabled && 349 (simulatedPlatformVersion == 0 || simulatedPlatformVersion >= 28); 350 NavigationBar navBar = 351 new NavigationBar(context, density, orientation, isRtl, isRtlSupported, 352 simulatedPlatformVersion, isQuickStepEnabled); 353 boolean isVertical = mBuilder.isNavBarVertical(); 354 int w = isVertical ? size : MATCH_PARENT; 355 int h = isVertical ? MATCH_PARENT : size; 356 RelativeLayout.LayoutParams params = createSysUiLayoutParams(w, h); 357 params.addRule(isVertical ? RelativeLayout.ALIGN_PARENT_END : RelativeLayout.ALIGN_PARENT_BOTTOM); 358 navBar.setLayoutParams(params); 359 navBar.setId(getId(ID_NAV_BAR)); 360 return navBar; 361 } 362 addSystemUiViews(@onNull View... views)363 private void addSystemUiViews(@NonNull View... views) { 364 for (View view : views) { 365 if (view != null) { 366 mSysUiRoot.addView(view); 367 } 368 } 369 } 370 getId(String name)371 private int getId(String name) { 372 return Bridge.getResourceId(ResourceType.ID, ID_PREFIX + name); 373 } 374 375 @SuppressWarnings("deprecation") 376 @Override requestFitSystemWindows()377 public void requestFitSystemWindows() { 378 // The framework call would usually bubble up to ViewRootImpl but, in layoutlib, Layout will 379 // act as view root for most purposes. That way, we can also save going through the Handler 380 // to dispatch the new applied insets. 381 ViewRootImpl root = AttachInfo_Accessor.getRootView(this); 382 if (root != null) { 383 ViewRootImpl_Accessor.dispatchApplyInsets(root, this); 384 } 385 } 386 387 /** 388 * A helper class to help initialize the Layout. 389 */ 390 static class Builder { 391 @NonNull 392 private final SessionParams mParams; 393 @NonNull 394 private final BridgeContext mContext; 395 private final RenderResources mResources; 396 397 private final boolean mWindowIsFloating; 398 private ResourceValue mWindowBackground; 399 private int mStatusBarSize; 400 private int mNavBarSize; 401 private int mNavBarOrientation; 402 private int mAppCompatActionBarSize; 403 private int mFrameworkActionBarSize; 404 private int mTitleBarSize; 405 private boolean mTranslucentStatus; 406 private boolean mTranslucentNav; 407 Builder(@onNull SessionParams params, @NonNull BridgeContext context)408 public Builder(@NonNull SessionParams params, @NonNull BridgeContext context) { 409 mParams = params; 410 mContext = context; 411 mResources = mParams.getResources(); 412 mWindowIsFloating = 413 getBooleanThemeFrameworkAttrValue(mResources, ATTR_WINDOW_FLOATING, true); 414 415 findBackground(); 416 417 if (!mParams.isForceNoDecor()) { 418 findStatusBar(); 419 findFrameworkBar(); 420 findAppCompatActionBar(); 421 findNavBar(); 422 } 423 } 424 findBackground()425 private void findBackground() { 426 if (!mParams.isBgColorOverridden()) { 427 mWindowBackground = mResources.findItemInTheme( 428 BridgeContext.createFrameworkAttrReference(ATTR_WINDOW_BACKGROUND)); 429 mWindowBackground = mResources.resolveResValue(mWindowBackground); 430 } 431 } 432 findStatusBar()433 private void findStatusBar() { 434 boolean windowFullScreen = 435 getBooleanThemeFrameworkAttrValue(mResources, ATTR_WINDOW_FULL_SCREEN, false); 436 if (!windowFullScreen && !mWindowIsFloating) { 437 mStatusBarSize = 438 getFrameworkAttrDimension(ATTR_STATUS_BAR_HEIGHT, DEFAULT_STATUS_BAR_HEIGHT); 439 mTranslucentStatus = 440 getBooleanThemeFrameworkAttrValue( 441 mResources, ATTR_WINDOW_TRANSLUCENT_STATUS, false); 442 } 443 } 444 445 /** 446 * The behavior is different whether the App is using AppCompat or not. 447 * <h1>With App compat :</h1> 448 * <li> framework ("android:") attributes have to effect 449 * <li> windowNoTile=true hides the AppCompatActionBar 450 * <li> windowActionBar=false throws an exception 451 */ findAppCompatActionBar()452 private void findAppCompatActionBar() { 453 if (mWindowIsFloating || !mContext.isAppCompatTheme()) { 454 return; 455 } 456 457 boolean windowNoTitle = 458 getBooleanThemeValue(mResources, 459 mContext.createAppCompatAttrReference(ATTR_WINDOW_NO_TITLE), false); 460 461 boolean windowActionBar = 462 getBooleanThemeValue(mResources, 463 mContext.createAppCompatAttrReference(ATTR_WINDOW_ACTION_BAR), true); 464 465 if (!windowNoTitle && windowActionBar) { 466 mAppCompatActionBarSize = 467 getDimension(mContext.createAppCompatAttrReference(ATTR_ACTION_BAR_SIZE), 468 DEFAULT_TITLE_BAR_HEIGHT); 469 } 470 } 471 472 /** 473 * Find if we should show either the titleBar or the framework ActionBar 474 * <p> 475 * <h1> Without App compat :</h1> 476 * <li> windowNoTitle has no effect 477 * <li> android:windowNoTile=true hides the <b>ActionBar</b> 478 * <li> android:windowActionBar=true/false toggles between ActionBar/TitleBar 479 * </ul> 480 * <pre> 481 * +------------------------------------------------------------+ 482 * | | android:windowNoTitle | 483 * |android: | TRUE | FALSE | 484 * |windowActionBar|---------------------+----------------------+ 485 * | TRUE | Nothing | ActionBar (Default) | 486 * | FALSE | Nothing | TitleBar | 487 * +---------------+--------------------------------------------+ 488 * </pre> 489 * 490 * @see #findAppCompatActionBar() 491 */ findFrameworkBar()492 private void findFrameworkBar() { 493 if (mWindowIsFloating) { 494 return; 495 } 496 boolean frameworkWindowNoTitle = 497 getBooleanThemeFrameworkAttrValue(mResources, ATTR_WINDOW_NO_TITLE, false); 498 499 // Check if an actionbar is needed 500 boolean isMenu = "menu".equals(mParams.getFlag(RenderParamsFlags.FLAG_KEY_ROOT_TAG)); 501 502 boolean windowActionBar = 503 getBooleanThemeFrameworkAttrValue(mResources, ATTR_WINDOW_ACTION_BAR, true); 504 505 if (!frameworkWindowNoTitle || isMenu) { 506 if (isMenu || windowActionBar) { 507 mFrameworkActionBarSize = 508 getFrameworkAttrDimension(ATTR_ACTION_BAR_SIZE, DEFAULT_TITLE_BAR_HEIGHT); 509 } else { 510 mTitleBarSize = getDimension( 511 mContext.createAppCompatAttrReference(ATTR_WINDOW_TITLE_SIZE), 512 DEFAULT_TITLE_BAR_HEIGHT); 513 } 514 } 515 } 516 findNavBar()517 private void findNavBar() { 518 if (hasSoftwareButtons() && !mWindowIsFloating) { 519 // get orientation 520 HardwareConfig hwConfig = mParams.getHardwareConfig(); 521 boolean barOnBottom = true; 522 523 if (hwConfig.getOrientation() == ScreenOrientation.LANDSCAPE) { 524 int shortSize = hwConfig.getScreenHeight(); 525 int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / 526 hwConfig.getDensity().getDpiValue(); 527 528 // 0-599dp: "phone" UI with bar on the side 529 // 600+dp: "tablet" UI with bar on the bottom 530 barOnBottom = shortSizeDp >= 600; 531 } 532 533 mNavBarOrientation = barOnBottom ? LinearLayout.HORIZONTAL : VERTICAL; 534 mNavBarSize = 535 getFrameworkAttrDimension( 536 barOnBottom ? ATTR_NAV_BAR_HEIGHT : ATTR_NAV_BAR_WIDTH, 537 DEFAULT_NAV_BAR_SIZE); 538 mTranslucentNav = 539 getBooleanThemeFrameworkAttrValue(mResources, ATTR_WINDOW_TRANSLUCENT_NAV, 540 false); 541 } 542 } 543 544 @SuppressWarnings("SameParameterValue") getDimension(@onNull ResourceReference attrRef, int defaultValue)545 private int getDimension(@NonNull ResourceReference attrRef, int defaultValue) { 546 ResourceValue value = mResources.findItemInTheme(attrRef); 547 value = mResources.resolveResValue(value); 548 if (value != null) { 549 TypedValue typedValue = ResourceHelper.getValue(attrRef.getName(), value.getValue(), 550 true); 551 if (typedValue != null) { 552 return (int) typedValue.getDimension(mContext.getMetrics()); 553 } 554 } 555 return defaultValue; 556 } 557 558 @SuppressWarnings("SameParameterValue") getFrameworkAttrDimension(@onNull String attr, int defaultValue)559 private int getFrameworkAttrDimension(@NonNull String attr, int defaultValue) { 560 return getDimension(BridgeContext.createFrameworkAttrReference(attr), defaultValue); 561 } 562 hasSoftwareButtons()563 private boolean hasSoftwareButtons() { 564 return mParams.getHardwareConfig().hasSoftwareButtons(); 565 } 566 567 /** 568 * Returns true if the nav bar is present and not translucent. 569 */ hasSolidNavBar()570 private boolean hasSolidNavBar() { 571 return hasNavBar() && !mTranslucentNav; 572 } 573 574 /** 575 * Returns true if the status bar is present and not translucent. 576 */ hasSolidStatusBar()577 private boolean hasSolidStatusBar() { 578 return hasStatusBar() && !mTranslucentStatus; 579 } 580 hasNavBar()581 private boolean hasNavBar() { 582 return Config.showOnScreenNavBar(mParams.getSimulatedPlatformVersion()) && 583 hasSoftwareButtons() && mNavBarSize > 0; 584 } 585 hasTitleBar()586 private boolean hasTitleBar() { 587 return mTitleBarSize > 0; 588 } 589 hasStatusBar()590 private boolean hasStatusBar() { 591 return mStatusBarSize > 0; 592 } 593 hasAppCompatActionBar()594 private boolean hasAppCompatActionBar() { 595 return mAppCompatActionBarSize > 0; 596 } 597 598 /** 599 * Return true if the nav bar is present and is vertical. 600 */ isNavBarVertical()601 private boolean isNavBarVertical() { 602 return hasNavBar() && mNavBarOrientation == VERTICAL; 603 } 604 hasFrameworkActionBar()605 private boolean hasFrameworkActionBar() { 606 return mFrameworkActionBarSize > 0; 607 } 608 hasNotch()609 private boolean hasNotch() { 610 return !mParams.isForceNoDecor(); 611 } 612 } 613 } 614