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