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