Merge changes I5413ef48,Id7261e4a into main

* changes:
  Add APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND
  Add bounding rects to the captionBar() inset source
diff --git a/core/api/current.txt b/core/api/current.txt
index 05d510d..d447491 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -54257,8 +54257,10 @@
     method public void setSystemBarsAppearance(int, int);
     method public void setSystemBarsBehavior(int);
     method public void show(int);
+    field @FlaggedApi("android.view.flags.customizable_window_headers") public static final int APPEARANCE_LIGHT_CAPTION_BARS = 256; // 0x100
     field public static final int APPEARANCE_LIGHT_NAVIGATION_BARS = 16; // 0x10
     field public static final int APPEARANCE_LIGHT_STATUS_BARS = 8; // 0x8
+    field @FlaggedApi("android.view.flags.customizable_window_headers") public static final int APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND = 128; // 0x80
     field public static final int BEHAVIOR_DEFAULT = 1; // 0x1
     field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
     field @Deprecated public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index cc2cd79..b7542dc 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -26,6 +27,7 @@
 import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.animation.Interpolator;
+import android.view.flags.Flags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -78,6 +80,20 @@
     int APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS = 1 << 6;
 
     /**
+     * Makes the caption bar transparent.
+     */
+    @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
+    int APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND = 1 << 7;
+
+    /**
+     * When {@link WindowInsetsController#APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND} is set,
+     * changes the foreground color of the caption bars so that the items on the bar can be read
+     * clearly on light backgrounds.
+     */
+    @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
+    int APPEARANCE_LIGHT_CAPTION_BARS = 1 << 8;
+
+    /**
      * Determines the appearance of system bars.
      * @hide
      */
@@ -85,7 +101,8 @@
     @IntDef(flag = true, value = {APPEARANCE_OPAQUE_STATUS_BARS, APPEARANCE_OPAQUE_NAVIGATION_BARS,
             APPEARANCE_LOW_PROFILE_BARS, APPEARANCE_LIGHT_STATUS_BARS,
             APPEARANCE_LIGHT_NAVIGATION_BARS, APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS,
-            APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS})
+            APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS,
+            APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND, APPEARANCE_LIGHT_CAPTION_BARS})
     @interface Appearance {
     }
 
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 28e7098..2018993 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -435,6 +435,9 @@
          Text varies in size, we will calculate that width separately. -->
     <dimen name="desktop_mode_app_details_width_minus_text">62dp</dimen>
 
+    <!-- 22dp padding + 24dp app icon + 16dp expand button + 86dp text (max) -->
+    <dimen name="desktop_mode_app_details_max_width">148dp</dimen>
+
     <!-- The width of the maximize menu in desktop mode. -->
     <dimen name="desktop_mode_maximize_menu_width">287dp</dimen>
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 3f0a281..185365b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -299,12 +299,34 @@
             ActivityManager.RunningTaskInfo taskInfo,
             boolean applyStartTransactionOnDraw,
             boolean shouldSetTaskPositionAndCrop) {
+        final int captionLayoutId = getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
         relayoutParams.reset();
         relayoutParams.mRunningTaskInfo = taskInfo;
-        relayoutParams.mLayoutResId =
-            getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
+        relayoutParams.mLayoutResId = captionLayoutId;
         relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
         relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
+
+        // The "app controls" type caption bar should report the occluding elements as bounding
+        // rects to the insets system so that apps can draw in the empty space left in the center.
+        if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor) {
+            // The "app chip" section of the caption bar, it's aligned to the left and its width
+            // varies depending on the length of the app name, but we'll report its max width for
+            // now.
+            // TODO(b/316387515): consider reporting the true width after it's been laid out.
+            final RelayoutParams.OccludingCaptionElement appChipElement =
+                    new RelayoutParams.OccludingCaptionElement();
+            appChipElement.mWidthResId = R.dimen.desktop_mode_app_details_max_width;
+            appChipElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.START;
+            relayoutParams.mOccludingCaptionElements.add(appChipElement);
+            // The "controls" section of the caption bar (maximize, close btns). These are aligned
+            // to the right of the caption bar and have a fixed width.
+            // TODO(b/316387515): add additional padding for an exclusive drag-move region.
+            final RelayoutParams.OccludingCaptionElement controlsElement =
+                    new RelayoutParams.OccludingCaptionElement();
+            controlsElement.mWidthResId = R.dimen.desktop_mode_right_edge_buttons_width;
+            controlsElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.END;
+            relayoutParams.mOccludingCaptionElements.add(controlsElement);
+        }
         if (DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ taskInfo.isFocused)) {
             relayoutParams.mShadowRadiusId = taskInfo.isFocused
                     ? R.dimen.freeform_decor_shadow_focused_thickness
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 35d5940..dc65855 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -50,7 +50,10 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Supplier;
 
 /**
@@ -293,13 +296,36 @@
             outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused);
 
             // Caption insets
-            mCaptionInsetsRect.set(taskBounds);
             if (mIsCaptionVisible) {
-                mCaptionInsetsRect.bottom =
-                        mCaptionInsetsRect.top + outResult.mCaptionHeight;
+                // Caption inset is the full width of the task with the |captionHeight| and
+                // positioned at the top of the task bounds, also in absolute coordinates.
+                // So just reuse the task bounds and adjust the bottom coordinate.
+                mCaptionInsetsRect.set(taskBounds);
+                mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + outResult.mCaptionHeight;
+
+                // Caption bounding rectangles: these are optional, and are used to present finer
+                // insets than traditional |Insets| to apps about where their content is occluded.
+                // These are also in absolute coordinates.
+                final Rect[] boundingRects;
+                final int numOfElements = params.mOccludingCaptionElements.size();
+                if (numOfElements == 0) {
+                    boundingRects = null;
+                } else {
+                    boundingRects = new Rect[numOfElements];
+                    for (int i = 0; i < numOfElements; i++) {
+                        final OccludingCaptionElement element =
+                                params.mOccludingCaptionElements.get(i);
+                        final int elementWidthPx =
+                                resources.getDimensionPixelSize(element.mWidthResId);
+                        boundingRects[i] =
+                                calculateBoundingRect(element, elementWidthPx, mCaptionInsetsRect);
+                    }
+                }
+
+                // Add this caption as an inset source.
                 wct.addInsetsSource(mTaskInfo.token,
                         mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect,
-                        null /* boundingRects */);
+                        boundingRects);
                 wct.addInsetsSource(mTaskInfo.token,
                         mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(),
                         mCaptionInsetsRect, null /* boundingRects */);
@@ -378,6 +404,20 @@
         }
     }
 
+    private Rect calculateBoundingRect(@NonNull OccludingCaptionElement element,
+            int elementWidthPx, @NonNull Rect captionRect) {
+        switch (element.mAlignment) {
+            case START -> {
+                return new Rect(0, 0, elementWidthPx, captionRect.height());
+            }
+            case END -> {
+                return new Rect(captionRect.width() - elementWidthPx, 0,
+                        captionRect.width(), captionRect.height());
+            }
+        }
+        throw new IllegalArgumentException("Unexpected alignment " + element.mAlignment);
+    }
+
     /**
      * Checks if task has entered/exited immersive mode and requires a change in caption visibility.
      */
@@ -555,8 +595,9 @@
         int mLayoutResId;
         int mCaptionHeightId;
         int mCaptionWidthId;
-        int mShadowRadiusId;
+        final List<OccludingCaptionElement> mOccludingCaptionElements = new ArrayList<>();
 
+        int mShadowRadiusId;
         int mCornerRadius;
 
         Configuration mWindowDecorConfig;
@@ -568,14 +609,28 @@
             mLayoutResId = Resources.ID_NULL;
             mCaptionHeightId = Resources.ID_NULL;
             mCaptionWidthId = Resources.ID_NULL;
-            mShadowRadiusId = Resources.ID_NULL;
+            mOccludingCaptionElements.clear();
 
+            mShadowRadiusId = Resources.ID_NULL;
             mCornerRadius = 0;
 
             mApplyStartTransactionOnDraw = false;
             mSetTaskPositionAndCrop = false;
             mWindowDecorConfig = null;
         }
+
+        /**
+         * Describes elements within the caption bar that could occlude app content, and should be
+         * sent as bounding rectangles to the insets system.
+         */
+        static class OccludingCaptionElement {
+            int mWidthResId;
+            Alignment mAlignment;
+
+            enum Alignment {
+                START, END
+            }
+        }
     }
 
     static class RelayoutResult<T extends View & TaskFocusStateConsumer> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
index 144373f..2309c54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
@@ -8,6 +8,8 @@
 import android.graphics.Color
 import android.view.View
 import android.view.View.OnLongClickListener
+import android.view.WindowInsetsController.APPEARANCE_LIGHT_CAPTION_BARS
+import android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND
 import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.TextView
@@ -79,6 +81,9 @@
 
     @ColorInt
     private fun getCaptionBackgroundColor(taskInfo: RunningTaskInfo): Int {
+        if (isTransparentBackgroundRequested(taskInfo)) {
+            return Color.TRANSPARENT
+        }
         val materialColorAttr: Int =
             if (isDarkMode()) {
                 if (!taskInfo.isFocused) {
@@ -102,6 +107,10 @@
     @ColorInt
     private fun getAppNameAndButtonColor(taskInfo: RunningTaskInfo): Int {
         val materialColorAttr = when {
+            isTransparentBackgroundRequested(taskInfo) &&
+                    isLightCaptionBar(taskInfo) -> materialColorOnSecondaryContainer
+            isTransparentBackgroundRequested(taskInfo) &&
+                    !isLightCaptionBar(taskInfo) -> materialColorOnSurface
             isDarkMode() -> materialColorOnSurface
             else -> materialColorOnSecondaryContainer
         }
@@ -132,6 +141,16 @@
                 Configuration.UI_MODE_NIGHT_YES
     }
 
+    private fun isTransparentBackgroundRequested(taskInfo: RunningTaskInfo): Boolean {
+        val appearance = taskInfo.taskDescription?.statusBarAppearance ?: 0
+        return (appearance and APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND) != 0
+    }
+
+    private fun isLightCaptionBar(taskInfo: RunningTaskInfo): Boolean {
+        val appearance = taskInfo.taskDescription?.statusBarAppearance ?: 0
+        return (appearance and APPEARANCE_LIGHT_CAPTION_BARS) != 0
+    }
+
     companion object {
         private const val TAG = "DesktopModeAppControlsWindowDecorationViewHolder"
         private const val DARK_THEME_UNFOCUSED_OPACITY = 140 // 55%