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