Add safe rectangle and caption bar to ScalablUI

- created new scable ui configurations for safe region and toolbar

Bug: 405200165
Test: manual
Flag: com.android.systemui.car.display_compatibility_auto_decor_safe_region
Change-Id: I1a878bab29f654df289f993a432493773ee449a6
diff --git a/car-scalable-ui-lib/src/com/android/car/scalableui/loader/xml/PanelStateXmlParser.java b/car-scalable-ui-lib/src/com/android/car/scalableui/loader/xml/PanelStateXmlParser.java
index 08c65e1..c76e46c 100644
--- a/car-scalable-ui-lib/src/com/android/car/scalableui/loader/xml/PanelStateXmlParser.java
+++ b/car-scalable-ui-lib/src/com/android/car/scalableui/loader/xml/PanelStateXmlParser.java
@@ -108,6 +108,7 @@
 
     // --- Bounds Tags ---
     public static final String BOUNDS_TAG = "Bounds";
+    public static final String SAFE_BOUNDS_TAG = "SafeBounds";
     public static final String LEFT_ATTRIBUTE = "left";
     public static final String RIGHT_ATTRIBUTE = "right";
     public static final String TOP_ATTRIBUTE = "top";
@@ -264,6 +265,9 @@
                 case BOUNDS_TAG:
                     variantBuilder.setBounds(parseBounds(context, parser).getRect());
                     break;
+                case SAFE_BOUNDS_TAG:
+                    variantBuilder.setSafeBounds(parseBounds(context, parser).getRect());
+                    break;
                 case CORNER_TAG:
                     variantBuilder.setCornerRadius(parseCorner(context, parser).getRadius());
                     break;
@@ -336,8 +340,13 @@
     @NonNull
     private static Bounds parseBounds(@NonNull Context context, @NonNull XmlPullParser parser)
             throws IOException, XmlPullParserException {
-
-        parser.require(XmlPullParser.START_TAG, null, BOUNDS_TAG);
+        if (XmlPullParser.START_TAG != parser.getEventType()
+                || !(BOUNDS_TAG.equals(parser.getName())
+                || SAFE_BOUNDS_TAG.equals(parser.getName()))) {
+            throw new XmlPullParserException(
+                    "parseBounds called with wrong parser event type: " + parser.getEventType()
+                            + " or name: " + parser.getName());
+        }
         AttributeSet attrs = Xml.asAttributeSet(parser);
 
         Integer left = getDimensionPixelSize(context, attrs, LEFT_ATTRIBUTE, true);
diff --git a/car-scalable-ui-lib/src/com/android/car/scalableui/manager/StateManager.java b/car-scalable-ui-lib/src/com/android/car/scalableui/manager/StateManager.java
index d9bda02..b084eed 100644
--- a/car-scalable-ui-lib/src/com/android/car/scalableui/manager/StateManager.java
+++ b/car-scalable-ui-lib/src/com/android/car/scalableui/manager/StateManager.java
@@ -156,6 +156,7 @@
         panel.setDisplayId(panelState.getDisplayId());
         panel.setInsets(variant.getInsets());
         panel.setCornerRadius(variant.getCornerRadius());
+        panel.setSafeBounds(variant.getSafeBounds());
     }
 
     //TODO(b/390006880): make this part of configuration.
diff --git a/car-scalable-ui-lib/src/com/android/car/scalableui/model/Variant.java b/car-scalable-ui-lib/src/com/android/car/scalableui/model/Variant.java
index ed0f0e3..2f51853 100644
--- a/car-scalable-ui-lib/src/com/android/car/scalableui/model/Variant.java
+++ b/car-scalable-ui-lib/src/com/android/car/scalableui/model/Variant.java
@@ -46,13 +46,18 @@
     private final RectEvaluator mRectEvaluator = new RectEvaluator();
     private final IntEvaluator mIntEvaluator = new IntEvaluator();
 
-    @NonNull protected final String mId;
+    @NonNull
+    protected final String mId;
     private float mAlpha;
     private boolean mIsVisible;
     private int mLayer;
     private int mCornerRadius;
-    @NonNull private Rect mBounds;
-    @NonNull private Insets mInsets;
+    @NonNull
+    private Rect mBounds;
+    @NonNull
+    private Rect mSafeBounds;
+    @NonNull
+    private Insets mInsets;
 
     /**
      * Constructs a Variant object with the specified ID. This constructor is package-private and is
@@ -65,6 +70,7 @@
 
         // Initialize with default values
         mBounds = new Rect();
+        mSafeBounds = new Rect();
         mIsVisible = Visibility.DEFAULT_VISIBILITY;
         mLayer = Layer.DEFAULT_LAYER;
         mAlpha = Alpha.DEFAULT_ALPHA;
@@ -84,6 +90,7 @@
     Variant(@NonNull String id, @NonNull Variant base) {
         this(id);
         mBounds = new Rect(base.getBounds());
+        mSafeBounds = new Rect(base.getSafeBounds());
         mIsVisible = base.isVisible();
         mLayer = base.getLayer();
         mAlpha = base.getAlpha();
@@ -229,6 +236,25 @@
     }
 
     /**
+     * Returns the safe bounds of the variant.
+     *
+     * @return The safe bounds of the variant.
+     */
+    @NonNull
+    public Rect getSafeBounds() {
+        return mSafeBounds;
+    }
+
+    /**
+     * Sets the safe bounds of the variant.
+     *
+     * @param safeBounds The bounds to set.
+     */
+    protected void setSafeBounds(@NonNull Rect safeBounds) {
+        mSafeBounds = safeBounds;
+    }
+
+    /**
      * Returns the corner radius of the variant.
      *
      * @return The corner radius of the variant.
@@ -258,7 +284,7 @@
     /**
      * @return {@link Insets}.
      */
-    @Nullable
+    @NonNull
     public Insets getInsets() {
         return mInsets;
     }
@@ -286,6 +312,8 @@
                 + mLayer
                 + ", mBounds="
                 + mBounds
+                + ", mSafeBounds="
+                + mSafeBounds
                 + ", mCornerRadius="
                 + mCornerRadius
                 + ", mInsets="
@@ -295,14 +323,24 @@
 
     /** Builder for {@link Variant} objects. */
     public static class Builder {
-        @NonNull protected String mId;
-        @Nullable protected Float mAlpha;
-        @Nullable protected Boolean mIsVisible;
-        @Nullable protected Integer mLayer;
-        @Nullable protected Rect mBounds;
-        @Nullable protected Integer mCornerRadius;
-        @Nullable protected Insets mInsets;
-        @Nullable protected Variant mParent;
+        @NonNull
+        protected String mId;
+        @Nullable
+        protected Float mAlpha;
+        @Nullable
+        protected Boolean mIsVisible;
+        @Nullable
+        protected Integer mLayer;
+        @Nullable
+        protected Rect mBounds;
+        @Nullable
+        protected Rect mSafeBounds;
+        @Nullable
+        protected Integer mCornerRadius;
+        @Nullable
+        protected Insets mInsets;
+        @Nullable
+        protected Variant mParent;
 
         public Builder(@NonNull String id) {
             mId = id;
@@ -332,6 +370,15 @@
             return this;
         }
 
+        /**
+         * Sets safe bounds. This is an area generally not overlapped by display cutouts or insets
+         * for display compatibility apps to be drawn within.
+         */
+        public Builder setSafeBounds(@NonNull Rect safeBounds) {
+            mSafeBounds = safeBounds;
+            return this;
+        }
+
         /** Sets corner radius */
         public Builder setCornerRadius(@NonNull Integer cornerRadius) {
             mCornerRadius = cornerRadius;
@@ -372,6 +419,11 @@
             if (mBounds != null) {
                 variant.setBounds(new Rect(mBounds)); // Defensive copy
             }
+            if (mSafeBounds != null) {
+                variant.setSafeBounds(new Rect(mSafeBounds)); // Defensive copy
+            } else if (mBounds != null) {
+                variant.setSafeBounds(new Rect(mBounds)); // Defensive copy
+            }
             if (mCornerRadius != null) {
                 variant.setCornerRadius(mCornerRadius);
             }
diff --git a/car-scalable-ui-lib/src/com/android/car/scalableui/panel/Panel.java b/car-scalable-ui-lib/src/com/android/car/scalableui/panel/Panel.java
index 3f7318b..414dd07 100644
--- a/car-scalable-ui-lib/src/com/android/car/scalableui/panel/Panel.java
+++ b/car-scalable-ui-lib/src/com/android/car/scalableui/panel/Panel.java
@@ -40,6 +40,23 @@
     void setBounds(Rect bounds);
 
     /**
+     * Gets safe bounds. This is an area generally not overlapped by display cutouts or insets
+     * for display compatibility apps to be drawn within.
+     *
+     * @return The bounding safe rectangle.
+     */
+    @NonNull
+    Rect getSafeBounds();
+
+    /**
+     * Sets safe bounds. This is an area generally not overlapped by display cutouts or insets
+     * for display compatibility apps to be drawn within.
+     *
+     * @param safeBounds The new bounding safe rectangle.
+     */
+    void setSafeBounds(@NonNull Rect safeBounds);
+
+    /**
      * Gets the layer of this panel.
      * Panels with higher layer values are drawn on top of panels with lower layer values.
      *
diff --git a/car-scalable-ui-lib/src/com/android/car/scalableui/panel/PanelView.java b/car-scalable-ui-lib/src/com/android/car/scalableui/panel/PanelView.java
index b761903..15e04fe 100644
--- a/car-scalable-ui-lib/src/com/android/car/scalableui/panel/PanelView.java
+++ b/car-scalable-ui-lib/src/com/android/car/scalableui/panel/PanelView.java
@@ -75,6 +75,18 @@
         setBottom(bounds.bottom);
     }
 
+    @NonNull
+    @Override
+    public Rect getSafeBounds() {
+        // no-op
+        return new Rect();
+    }
+
+    @Override
+    public void setSafeBounds(@NonNull Rect safeBounds) {
+        // no-op
+    }
+
     public int getLayer() {
         return mLayer;
     }