Merge "Allow SystemBar configuration via XML." into rvc-qpr-dev am: 4dbcd829fb am: 36b52feeb7

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12181454

Change-Id: I6ef84cef8f71763baba5f130f16c36b4aaf427a6
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index cf967c0..039f2c0 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -24,12 +24,35 @@
 
     <bool name="config_enableFullscreenUserSwitcher">true</bool>
 
-    <!-- configure which system ui bars should be displayed -->
+    <!-- Configure which system bars should be displayed. -->
     <bool name="config_enableTopNavigationBar">true</bool>
     <bool name="config_enableLeftNavigationBar">false</bool>
     <bool name="config_enableRightNavigationBar">false</bool>
     <bool name="config_enableBottomNavigationBar">true</bool>
 
+    <!-- Configure the type of each system bar. Each system bar must have a unique type. -->
+    <!--    STATUS_BAR = 0-->
+    <!--    NAVIGATION_BAR = 1-->
+    <!--    STATUS_BAR_EXTRA = 2-->
+    <!--    NAVIGATION_BAR_EXTRA = 3-->
+    <integer name="config_topSystemBarType">0</integer>
+    <integer name="config_leftSystemBarType">2</integer>
+    <integer name="config_rightSystemBarType">3</integer>
+    <integer name="config_bottomSystemBarType">1</integer>
+
+    <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g.
+         if both top bar and left bar are enabled, it creates an overlapping space in the upper left
+         corner), the system bar with the higher z-order takes the overlapping space and padding is
+         applied to the other bar.-->
+    <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a
+         RuntimeException, since their placing order cannot be determined. Bars that do not overlap
+         are allowed to have the same z-order. -->
+    <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's.    -->
+    <integer name="config_topSystemBarZOrder">1</integer>
+    <integer name="config_leftSystemBarZOrder">0</integer>
+    <integer name="config_rightSystemBarZOrder">0</integer>
+    <integer name="config_bottomSystemBarZOrder">10</integer>
+
     <!-- Disable normal notification rendering; we handle that ourselves -->
     <bool name="config_renderNotifications">false</bool>
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index 35b2080..9584850 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -16,12 +16,8 @@
 
 package com.android.systemui.car.navigationbar;
 
-import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_GESTURES;
 import static android.view.InsetsState.containsType;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 
@@ -30,13 +26,11 @@
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.PixelFormat;
 import android.inputmethodservice.InputMethodService;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.view.Display;
-import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowInsetsController;
@@ -47,7 +41,6 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.RegisterStatusBarResult;
 import com.android.internal.view.AppearanceRegion;
-import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarDeviceProvisionedListener;
@@ -76,7 +69,6 @@
 
 /** Navigation bars customized for the automotive use case. */
 public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks {
-
     private final Resources mResources;
     private final CarNavigationBarController mCarNavigationBarController;
     private final SysuiDarkIconDispatcher mStatusBarIconController;
@@ -93,6 +85,7 @@
     private final Lazy<StatusBarIconController> mIconControllerLazy;
 
     private final int mDisplayId;
+    private final SystemBarConfigs mSystemBarConfigs;
 
     private StatusBarSignalPolicy mSignalPolicy;
     private ActivityManagerWrapper mActivityManagerWrapper;
@@ -141,7 +134,8 @@
             IStatusBarService barService,
             Lazy<KeyguardStateController> keyguardStateControllerLazy,
             Lazy<PhoneStatusBarPolicy> iconPolicyLazy,
-            Lazy<StatusBarIconController> iconControllerLazy
+            Lazy<StatusBarIconController> iconControllerLazy,
+            SystemBarConfigs systemBarConfigs
     ) {
         super(context);
         mResources = resources;
@@ -158,6 +152,7 @@
         mKeyguardStateControllerLazy = keyguardStateControllerLazy;
         mIconPolicyLazy = iconPolicyLazy;
         mIconControllerLazy = iconControllerLazy;
+        mSystemBarConfigs = systemBarConfigs;
 
         mDisplayId = context.getDisplayId();
     }
@@ -344,103 +339,63 @@
     private void buildNavBarContent() {
         mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
         if (mTopNavigationBarView != null) {
+            mSystemBarConfigs.insetSystemBar(SystemBarConfigs.TOP, mTopNavigationBarView);
             mTopNavigationBarWindow.addView(mTopNavigationBarView);
         }
 
         mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
         if (mBottomNavigationBarView != null) {
+            mSystemBarConfigs.insetSystemBar(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
             mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
         }
 
         mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
         if (mLeftNavigationBarView != null) {
+            mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, mLeftNavigationBarView);
             mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
         }
 
         mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
         if (mRightNavigationBarView != null) {
+            mSystemBarConfigs.insetSystemBar(SystemBarConfigs.RIGHT, mRightNavigationBarView);
             mRightNavigationBarWindow.addView(mRightNavigationBarView);
         }
     }
 
     private void attachNavBarWindows() {
-        if (mTopNavigationBarWindow != null) {
-            int height = mResources.getDimensionPixelSize(
-                    com.android.internal.R.dimen.status_bar_height);
-            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT,
-                    height,
-                    WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
-                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                    PixelFormat.TRANSLUCENT);
-            lp.setTitle("TopCarNavigationBar");
-            lp.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
-            lp.setFitInsetsTypes(0);
-            lp.windowAnimations = 0;
-            lp.gravity = Gravity.TOP;
-            mWindowManager.addView(mTopNavigationBarWindow, lp);
-        }
+        mSystemBarConfigs.getSystemBarSidesByZOrder().forEach(this::attachNavBarBySide);
+    }
 
-        if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
-            mBottomNavBarVisible = true;
-            int height = mResources.getDimensionPixelSize(
-                    com.android.internal.R.dimen.navigation_bar_height);
+    private void attachNavBarBySide(int side) {
+        switch(side) {
+            case SystemBarConfigs.TOP:
+                if (mTopNavigationBarWindow != null) {
+                    mWindowManager.addView(mTopNavigationBarWindow,
+                            mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.TOP));
+                }
+                break;
+            case SystemBarConfigs.BOTTOM:
+                if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
+                    mBottomNavBarVisible = true;
 
-            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT,
-                    height,
-                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                    PixelFormat.TRANSLUCENT);
-            lp.setTitle("BottomCarNavigationBar");
-            lp.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR, ITYPE_BOTTOM_GESTURES};
-            lp.windowAnimations = 0;
-            lp.gravity = Gravity.BOTTOM;
-            mWindowManager.addView(mBottomNavigationBarWindow, lp);
-        }
-
-        if (mLeftNavigationBarWindow != null) {
-            int width = mResources.getDimensionPixelSize(
-                    R.dimen.car_left_navigation_bar_width);
-            WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
-                    width, ViewGroup.LayoutParams.MATCH_PARENT,
-                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                    PixelFormat.TRANSLUCENT);
-            leftlp.setTitle("LeftCarNavigationBar");
-            leftlp.providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
-            leftlp.setFitInsetsTypes(0);
-            leftlp.windowAnimations = 0;
-            leftlp.gravity = Gravity.LEFT;
-            mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
-        }
-
-        if (mRightNavigationBarWindow != null) {
-            int width = mResources.getDimensionPixelSize(
-                    R.dimen.car_right_navigation_bar_width);
-            WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
-                    width, ViewGroup.LayoutParams.MATCH_PARENT,
-                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                    PixelFormat.TRANSLUCENT);
-            rightlp.setTitle("RightCarNavigationBar");
-            rightlp.providesInsetsTypes = new int[]{ITYPE_EXTRA_NAVIGATION_BAR};
-            rightlp.setFitInsetsTypes(0);
-            rightlp.windowAnimations = 0;
-            rightlp.gravity = Gravity.RIGHT;
-            mWindowManager.addView(mRightNavigationBarWindow, rightlp);
+                    mWindowManager.addView(mBottomNavigationBarWindow,
+                            mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.BOTTOM));
+                }
+                break;
+            case SystemBarConfigs.LEFT:
+                if (mLeftNavigationBarWindow != null) {
+                    mWindowManager.addView(mLeftNavigationBarWindow,
+                            mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.LEFT));
+                }
+                break;
+            case SystemBarConfigs.RIGHT:
+                if (mRightNavigationBarWindow != null) {
+                    mWindowManager.addView(mRightNavigationBarWindow,
+                            mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.RIGHT));
+                }
+                break;
+            default:
+                return;
         }
     }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
index ca780ae..fe26040 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
@@ -22,7 +22,6 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.systemui.R;
 import com.android.systemui.car.hvac.HvacController;
 
 import javax.inject.Inject;
@@ -61,7 +60,8 @@
             NavigationBarViewFactory navigationBarViewFactory,
             ButtonSelectionStateController buttonSelectionStateController,
             Lazy<HvacController> hvacControllerLazy,
-            ButtonRoleHolderController buttonRoleHolderController) {
+            ButtonRoleHolderController buttonRoleHolderController,
+            SystemBarConfigs systemBarConfigs) {
         mContext = context;
         mNavigationBarViewFactory = navigationBarViewFactory;
         mButtonSelectionStateController = buttonSelectionStateController;
@@ -69,10 +69,10 @@
         mButtonRoleHolderController = buttonRoleHolderController;
 
         // Read configuration.
-        mShowTop = mContext.getResources().getBoolean(R.bool.config_enableTopNavigationBar);
-        mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
-        mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
-        mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+        mShowTop = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.TOP);
+        mShowBottom = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.BOTTOM);
+        mShowLeft = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.LEFT);
+        mShowRight = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.RIGHT);
     }
 
     /**
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 0ced402..ab401bb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -16,14 +16,10 @@
 
 package com.android.systemui.car.navigationbar;
 
-import static android.view.WindowInsets.Type.systemBars;
-
 import android.content.Context;
-import android.graphics.Insets;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.WindowInsets;
 import android.widget.LinearLayout;
 
 import com.android.systemui.Dependency;
@@ -80,30 +76,6 @@
         setFocusable(false);
     }
 
-    @Override
-    public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
-        applyMargins(windowInsets.getInsets(systemBars()));
-        return windowInsets;
-    }
-
-    private void applyMargins(Insets insets) {
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            if (child.getLayoutParams() instanceof LayoutParams) {
-                LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                if (lp.rightMargin != insets.right || lp.leftMargin != insets.left
-                        || lp.topMargin != insets.top || lp.bottomMargin != insets.bottom) {
-                    lp.rightMargin = insets.right;
-                    lp.leftMargin = insets.left;
-                    lp.topMargin = insets.top;
-                    lp.bottomMargin = insets.bottom;
-                    child.requestLayout();
-                }
-            }
-        }
-    }
-
     // Used to forward touch events even if the touch was initiated from a child component
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
new file mode 100644
index 0000000..3527bf9
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.navigationbar;
+
+import android.annotation.IntDef;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.InsetsState;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Reads configs for system bars for each side (TOP, BOTTOM, LEFT, and RIGHT) and returns the
+ * corresponding {@link android.view.WindowManager.LayoutParams} per the configuration.
+ */
+@Singleton
+public class SystemBarConfigs {
+
+    private static final String TAG = SystemBarConfigs.class.getSimpleName();
+    // The z-order from which system bars will start to appear on top of HUN's.
+    private static final int HUN_ZORDER = 10;
+
+    @IntDef(value = {TOP, BOTTOM, LEFT, RIGHT})
+    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+    private @interface SystemBarSide {
+    }
+
+    public static final int TOP = 0;
+    public static final int BOTTOM = 1;
+    public static final int LEFT = 2;
+    public static final int RIGHT = 3;
+
+    /*
+        NOTE: The elements' order in the map below must be preserved as-is since the correct
+        corresponding values are obtained by the index.
+     */
+    private static final int[] BAR_TYPE_MAP = {
+            InsetsState.ITYPE_STATUS_BAR,
+            InsetsState.ITYPE_NAVIGATION_BAR,
+            InsetsState.ITYPE_CLIMATE_BAR,
+            InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
+    };
+
+    private static final Map<@SystemBarSide Integer, Integer> BAR_GRAVITY_MAP = new ArrayMap<>();
+    private static final Map<@SystemBarSide Integer, String> BAR_TITLE_MAP = new ArrayMap<>();
+    private static final Map<@SystemBarSide Integer, Integer> BAR_GESTURE_MAP = new ArrayMap<>();
+
+    private final Resources mResources;
+    private final Map<@SystemBarSide Integer, SystemBarConfig> mSystemBarConfigMap =
+            new ArrayMap<>();
+    private final List<@SystemBarSide Integer> mSystemBarSidesByZOrder = new ArrayList<>();
+
+    private boolean mTopNavBarEnabled;
+    private boolean mBottomNavBarEnabled;
+    private boolean mLeftNavBarEnabled;
+    private boolean mRightNavBarEnabled;
+
+    @Inject
+    public SystemBarConfigs(@Main Resources resources) {
+        mResources = resources;
+
+        populateMaps();
+        readConfigs();
+        checkEnabledBarsHaveUniqueBarTypes();
+        setInsetPaddingsForOverlappingCorners();
+        sortSystemBarSidesByZOrder();
+    }
+
+    protected WindowManager.LayoutParams getLayoutParamsBySide(@SystemBarSide int side) {
+        return mSystemBarConfigMap.get(side) != null
+                ? mSystemBarConfigMap.get(side).getLayoutParams() : null;
+    }
+
+    protected boolean getEnabledStatusBySide(@SystemBarSide int side) {
+        switch (side) {
+            case TOP:
+                return mTopNavBarEnabled;
+            case BOTTOM:
+                return mBottomNavBarEnabled;
+            case LEFT:
+                return mLeftNavBarEnabled;
+            case RIGHT:
+                return mRightNavBarEnabled;
+            default:
+                return false;
+        }
+    }
+
+    protected void insetSystemBar(@SystemBarSide int side, CarNavigationBarView view) {
+        int[] paddings = mSystemBarConfigMap.get(side).getPaddings();
+        view.setPadding(paddings[2], paddings[0], paddings[3], paddings[1]);
+    }
+
+    protected List<Integer> getSystemBarSidesByZOrder() {
+        return mSystemBarSidesByZOrder;
+    }
+
+    @VisibleForTesting
+    protected static int getHunZOrder() {
+        return HUN_ZORDER;
+    }
+
+    private static void populateMaps() {
+        BAR_GRAVITY_MAP.put(TOP, Gravity.TOP);
+        BAR_GRAVITY_MAP.put(BOTTOM, Gravity.BOTTOM);
+        BAR_GRAVITY_MAP.put(LEFT, Gravity.LEFT);
+        BAR_GRAVITY_MAP.put(RIGHT, Gravity.RIGHT);
+
+        BAR_TITLE_MAP.put(TOP, "TopCarSystemBar");
+        BAR_TITLE_MAP.put(BOTTOM, "BottomCarSystemBar");
+        BAR_TITLE_MAP.put(LEFT, "LeftCarSystemBar");
+        BAR_TITLE_MAP.put(RIGHT, "RightCarSystemBar");
+
+        BAR_GESTURE_MAP.put(TOP, InsetsState.ITYPE_TOP_GESTURES);
+        BAR_GESTURE_MAP.put(BOTTOM, InsetsState.ITYPE_BOTTOM_GESTURES);
+        BAR_GESTURE_MAP.put(LEFT, InsetsState.ITYPE_LEFT_GESTURES);
+        BAR_GESTURE_MAP.put(RIGHT, InsetsState.ITYPE_RIGHT_GESTURES);
+    }
+
+    private void readConfigs() {
+        mTopNavBarEnabled = mResources.getBoolean(R.bool.config_enableTopNavigationBar);
+        mBottomNavBarEnabled = mResources.getBoolean(R.bool.config_enableBottomNavigationBar);
+        mLeftNavBarEnabled = mResources.getBoolean(R.bool.config_enableLeftNavigationBar);
+        mRightNavBarEnabled = mResources.getBoolean(R.bool.config_enableRightNavigationBar);
+
+        if (mTopNavBarEnabled) {
+            SystemBarConfig topBarConfig =
+                    new SystemBarConfigBuilder()
+                            .setSide(TOP)
+                            .setGirth(mResources.getDimensionPixelSize(
+                                    com.android.internal.R.dimen.status_bar_height))
+                            .setBarType(mResources.getInteger(R.integer.config_topSystemBarType))
+                            .setZOrder(mResources.getInteger(R.integer.config_topSystemBarZOrder))
+                            .build();
+            mSystemBarConfigMap.put(TOP, topBarConfig);
+        }
+
+        if (mBottomNavBarEnabled) {
+            SystemBarConfig bottomBarConfig =
+                    new SystemBarConfigBuilder()
+                            .setSide(BOTTOM)
+                            .setGirth(mResources.getDimensionPixelSize(
+                                    com.android.internal.R.dimen.navigation_bar_height))
+                            .setBarType(mResources.getInteger(R.integer.config_bottomSystemBarType))
+                            .setZOrder(
+                                    mResources.getInteger(R.integer.config_bottomSystemBarZOrder))
+                            .build();
+            mSystemBarConfigMap.put(BOTTOM, bottomBarConfig);
+        }
+
+        if (mLeftNavBarEnabled) {
+            SystemBarConfig leftBarConfig =
+                    new SystemBarConfigBuilder()
+                            .setSide(LEFT)
+                            .setGirth(mResources.getDimensionPixelSize(
+                                    R.dimen.car_left_navigation_bar_width))
+                            .setBarType(mResources.getInteger(R.integer.config_leftSystemBarType))
+                            .setZOrder(mResources.getInteger(R.integer.config_leftSystemBarZOrder))
+                            .build();
+            mSystemBarConfigMap.put(LEFT, leftBarConfig);
+        }
+
+        if (mRightNavBarEnabled) {
+            SystemBarConfig rightBarConfig =
+                    new SystemBarConfigBuilder()
+                            .setSide(RIGHT)
+                            .setGirth(mResources.getDimensionPixelSize(
+                                    R.dimen.car_right_navigation_bar_width))
+                            .setBarType(mResources.getInteger(R.integer.config_rightSystemBarType))
+                            .setZOrder(mResources.getInteger(R.integer.config_rightSystemBarZOrder))
+                            .build();
+            mSystemBarConfigMap.put(RIGHT, rightBarConfig);
+        }
+    }
+
+    private void checkEnabledBarsHaveUniqueBarTypes() throws RuntimeException {
+        Set<Integer> barTypesUsed = new ArraySet<>();
+        int enabledNavBarCount = mSystemBarConfigMap.size();
+
+        for (SystemBarConfig systemBarConfig : mSystemBarConfigMap.values()) {
+            barTypesUsed.add(systemBarConfig.getBarType());
+        }
+
+        // The number of bar types used cannot be fewer than that of enabled system bars.
+        if (barTypesUsed.size() < enabledNavBarCount) {
+            throw new RuntimeException("Each enabled system bar must have a unique bar type. Check "
+                    + "the configuration in config.xml");
+        }
+    }
+
+    private void setInsetPaddingsForOverlappingCorners() {
+        setInsetPaddingForOverlappingCorner(TOP, LEFT);
+        setInsetPaddingForOverlappingCorner(TOP, RIGHT);
+        setInsetPaddingForOverlappingCorner(BOTTOM, LEFT);
+        setInsetPaddingForOverlappingCorner(BOTTOM, RIGHT);
+    }
+
+    private void setInsetPaddingForOverlappingCorner(@SystemBarSide int horizontalSide,
+            @SystemBarSide int verticalSide) {
+
+        if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) {
+            Log.w(TAG, "configureBarPaddings: Returning immediately since the horizontal and "
+                    + "vertical sides were not provided correctly.");
+            return;
+        }
+
+        SystemBarConfig horizontalBarConfig = mSystemBarConfigMap.get(horizontalSide);
+        SystemBarConfig verticalBarConfig = mSystemBarConfigMap.get(verticalSide);
+
+        if (verticalBarConfig != null && horizontalBarConfig != null) {
+            int horizontalBarZOrder = horizontalBarConfig.getZOrder();
+            int horizontalBarGirth = horizontalBarConfig.getGirth();
+            int verticalBarZOrder = verticalBarConfig.getZOrder();
+            int verticalBarGirth = verticalBarConfig.getGirth();
+
+            if (horizontalBarZOrder > verticalBarZOrder) {
+                verticalBarConfig.setPaddingBySide(horizontalSide, horizontalBarGirth);
+            } else if (horizontalBarZOrder < verticalBarZOrder) {
+                horizontalBarConfig.setPaddingBySide(verticalSide, verticalBarGirth);
+            } else {
+                throw new RuntimeException(
+                        BAR_TITLE_MAP.get(horizontalSide) + " " + BAR_TITLE_MAP.get(verticalSide)
+                                + " have the same Z-Order, and so their placing order cannot be "
+                                + "determined. Determine which bar should be placed on top of the "
+                                + "other bar and change the Z-order in config.xml accordingly."
+                );
+            }
+        }
+    }
+
+    private void sortSystemBarSidesByZOrder() {
+        List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());
+
+        systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {
+            @Override
+            public int compare(SystemBarConfig o1, SystemBarConfig o2) {
+                return o1.getZOrder() - o2.getZOrder();
+            }
+        });
+
+        systemBarsByZOrder.forEach(systemBarConfig -> {
+            mSystemBarSidesByZOrder.add(systemBarConfig.getSide());
+        });
+    }
+
+    private static boolean isHorizontalBar(@SystemBarSide int side) {
+        return  side == TOP || side == BOTTOM;
+    }
+
+    private static boolean isVerticalBar(@SystemBarSide int side) {
+        return side == LEFT || side == RIGHT;
+    }
+
+    private static final class SystemBarConfig {
+        private final int mSide;
+        private final int mBarType;
+        private final int mGirth;
+        private final int mZOrder;
+
+        private int[] mPaddings = new int[]{0, 0, 0, 0};
+
+        private SystemBarConfig(@SystemBarSide int side, int barType, int girth, int zOrder) {
+            mSide = side;
+            mBarType = barType;
+            mGirth = girth;
+            mZOrder = zOrder;
+        }
+
+        private int getSide() {
+            return mSide;
+        }
+
+        private int getBarType() {
+            return mBarType;
+        }
+
+        private int getGirth() {
+            return mGirth;
+        }
+
+        private int getZOrder() {
+            return mZOrder;
+        }
+
+        private int[] getPaddings() {
+            return mPaddings;
+        }
+
+        private WindowManager.LayoutParams getLayoutParams() {
+            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                    isHorizontalBar(mSide) ? ViewGroup.LayoutParams.MATCH_PARENT : mGirth,
+                    isHorizontalBar(mSide) ? mGirth : ViewGroup.LayoutParams.MATCH_PARENT,
+                    mapZOrderToBarType(mZOrder),
+                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+                    PixelFormat.TRANSLUCENT);
+            lp.setTitle(BAR_TITLE_MAP.get(mSide));
+            lp.providesInsetsTypes = new int[]{BAR_TYPE_MAP[mBarType], BAR_GESTURE_MAP.get(mSide)};
+            lp.setFitInsetsTypes(0);
+            lp.windowAnimations = 0;
+            lp.gravity = BAR_GRAVITY_MAP.get(mSide);
+            return lp;
+        }
+
+        private int mapZOrderToBarType(int zOrder) {
+            return zOrder >= HUN_ZORDER ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL
+                    : WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
+        }
+
+        private void setPaddingBySide(@SystemBarSide int side, int padding) {
+            mPaddings[side] = padding;
+        }
+    }
+
+    private static final class SystemBarConfigBuilder {
+        private int mSide;
+        private int mBarType;
+        private int mGirth;
+        private int mZOrder;
+
+        private SystemBarConfigBuilder setSide(@SystemBarSide int side) {
+            mSide = side;
+            return this;
+        }
+
+        private SystemBarConfigBuilder setBarType(int type) {
+            mBarType = type;
+            return this;
+        }
+
+        private SystemBarConfigBuilder setGirth(int girth) {
+            mGirth = girth;
+            return this;
+        }
+
+        private SystemBarConfigBuilder setZOrder(int zOrder) {
+            mZOrder = zOrder;
+            return this;
+        }
+
+        private SystemBarConfig build() {
+            return new SystemBarConfig(mSide, mBarType, mGirth, mZOrder);
+        }
+    }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
index dec8b8e..0b164a2 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
@@ -73,7 +73,8 @@
     private CarNavigationBarController createNavigationBarController() {
         return new CarNavigationBarController(mContext, mNavigationBarViewFactory,
                 mButtonSelectionStateController, () -> mHvacController,
-                mButtonRoleHolderController);
+                mButtonRoleHolderController,
+                new SystemBarConfigs(mTestableResources.getResources()));
     }
 
     @Test
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
index d9edfa96..2b5af71 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
@@ -142,7 +142,7 @@
                 mWindowManager, mDeviceProvisionedController, new CommandQueue(mContext),
                 mAutoHideController, mButtonSelectionStateListener, mHandler, mUiBgExecutor,
                 mBarService, () -> mKeyguardStateController, () -> mIconPolicy,
-                () -> mIconController);
+                () -> mIconController, new SystemBarConfigs(mTestableResources.getResources()));
     }
 
     @Test
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
new file mode 100644
index 0000000..8b15899
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car.navigationbar;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class SystemBarConfigsTest extends SysuiTestCase {
+
+    private SystemBarConfigs mSystemBarConfigs;
+    @Mock
+    private Resources mResources;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        setDefaultValidConfig();
+    }
+
+    @Test
+    public void onInit_allSystemBarsEnabled_eachHasUniqueBarTypes_doesNotThrowException() {
+        mSystemBarConfigs = new SystemBarConfigs(mResources);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void onInit_allSystemBarsEnabled_twoBarsHaveDuplicateType_throwsRuntimeException() {
+        when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
+        when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(0);
+
+        mSystemBarConfigs = new SystemBarConfigs(mResources);
+    }
+
+    @Test
+    public void onInit_allSystemBarsEnabled_systemBarSidesSortedByZOrder() {
+        mSystemBarConfigs = new SystemBarConfigs(mResources);
+        List<Integer> actualOrder = mSystemBarConfigs.getSystemBarSidesByZOrder();
+        List<Integer> expectedOrder = new ArrayList<>();
+        expectedOrder.add(SystemBarConfigs.LEFT);
+        expectedOrder.add(SystemBarConfigs.RIGHT);
+        expectedOrder.add(SystemBarConfigs.TOP);
+        expectedOrder.add(SystemBarConfigs.BOTTOM);
+
+        assertTrue(actualOrder.equals(expectedOrder));
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void onInit_intersectingBarsHaveSameZOrder_throwsRuntimeException() {
+        when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(33);
+        when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(33);
+
+        mSystemBarConfigs = new SystemBarConfigs(mResources);
+    }
+
+    @Test
+    public void getTopSystemBarLayoutParams_topBarEnabled_returnsTopSystemBarLayoutParams() {
+        mSystemBarConfigs = new SystemBarConfigs(mResources);
+        WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+                SystemBarConfigs.TOP);
+
+        assertNotNull(lp);
+    }
+
+    @Test
+    public void getTopSystemBarLayoutParams_topBarNotEnabled_returnsNull() {
+        when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false);
+        mSystemBarConfigs = new SystemBarConfigs(mResources);
+        WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+                SystemBarConfigs.TOP);
+
+        assertNull(lp);
+    }
+
+    @Test
+    public void topSystemBarHasHigherZOrderThanHuns_topSystemBarIsNavigationBarPanelType() {
+        when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(
+                SystemBarConfigs.getHunZOrder() + 1);
+        mSystemBarConfigs = new SystemBarConfigs(mResources);
+        WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+                SystemBarConfigs.TOP);
+
+        assertEquals(lp.type, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL);
+    }
+
+    @Test
+    public void topSystemBarHasLowerZOrderThanHuns_topSystemBarIsStatusBarAdditionalType() {
+        when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(
+                SystemBarConfigs.getHunZOrder() - 1);
+        mSystemBarConfigs = new SystemBarConfigs(mResources);
+        WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+                SystemBarConfigs.TOP);
+
+        assertEquals(lp.type, WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL);
+    }
+
+    // Set valid config where all system bars are enabled.
+    private void setDefaultValidConfig() {
+        when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true);
+        when(mResources.getBoolean(R.bool.config_enableBottomNavigationBar)).thenReturn(true);
+        when(mResources.getBoolean(R.bool.config_enableLeftNavigationBar)).thenReturn(true);
+        when(mResources.getBoolean(R.bool.config_enableRightNavigationBar)).thenReturn(true);
+
+        when(mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height)).thenReturn(100);
+        when(mResources.getDimensionPixelSize(
+                com.android.internal.R.dimen.navigation_bar_height)).thenReturn(100);
+        when(mResources.getDimensionPixelSize(R.dimen.car_left_navigation_bar_width)).thenReturn(
+                100);
+        when(mResources.getDimensionPixelSize(R.dimen.car_right_navigation_bar_width)).thenReturn(
+                100);
+
+        when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
+        when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(1);
+        when(mResources.getInteger(R.integer.config_leftSystemBarType)).thenReturn(2);
+        when(mResources.getInteger(R.integer.config_rightSystemBarType)).thenReturn(3);
+
+        when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(5);
+        when(mResources.getInteger(R.integer.config_bottomSystemBarZOrder)).thenReturn(10);
+        when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(2);
+        when(mResources.getInteger(R.integer.config_rightSystemBarZOrder)).thenReturn(3);
+    }
+}