Add border API to surface control

See go/sf-box-shadows-api for more details

Bug: b/367464660
Flag: com.android.window.flags.enable_border_settings
Test: atest SurfaceFlinger_test
Change-Id: I1190edb97693004d9f46058fd0165451470a65b3
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 158c548..2117c98 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -93,6 +93,7 @@
         "android/gui/StalledTransactionInfo.aidl",
         "android/**/TouchOcclusionMode.aidl",
         "android/gui/TrustedOverlay.aidl",
+        "android/gui/BorderSettings.aidl",
     ],
 }
 
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index ad95d1a..86bc97e 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -180,6 +180,7 @@
         SAFE_PARCEL(output.writeParcelableVector, listener.callbackIds);
     }
     SAFE_PARCEL(output.writeFloat, shadowRadius);
+    SAFE_PARCEL(output.writeParcelable, borderSettings);
     SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority);
     SAFE_PARCEL(output.writeFloat, frameRate);
     SAFE_PARCEL(output.writeByte, frameRateCompatibility);
@@ -328,6 +329,8 @@
         listeners.emplace_back(listener, callbackIds);
     }
     SAFE_PARCEL(input.readFloat, &shadowRadius);
+    SAFE_PARCEL(input.readParcelable, &borderSettings);
+
     SAFE_PARCEL(input.readInt32, &frameRateSelectionPriority);
     SAFE_PARCEL(input.readFloat, &frameRate);
     SAFE_PARCEL(input.readByte, &frameRateCompatibility);
@@ -727,6 +730,10 @@
         what |= eShadowRadiusChanged;
         shadowRadius = other.shadowRadius;
     }
+    if (other.what & eBorderSettingsChanged) {
+        what |= eBorderSettingsChanged;
+        borderSettings = other.borderSettings;
+    }
     if (other.what & eLutsChanged) {
         what |= eLutsChanged;
         luts = other.luts;
@@ -881,6 +888,7 @@
     CHECK_DIFF2(diff, eBackgroundColorChanged, other, bgColor, bgColorDataspace);
     if (other.what & eMetadataChanged) diff |= eMetadataChanged;
     CHECK_DIFF(diff, eShadowRadiusChanged, other, shadowRadius);
+    CHECK_DIFF(diff, eBorderSettingsChanged, other, borderSettings);
     CHECK_DIFF(diff, eDefaultFrameRateCompatibilityChanged, other, defaultFrameRateCompatibility);
     CHECK_DIFF(diff, eFrameRateSelectionPriority, other, frameRateSelectionPriority);
     CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9854274..60a2bf7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2222,6 +2222,19 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBorderSettings(
+        const sp<SurfaceControl>& sc, gui::BorderSettings settings) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eBorderSettingsChanged;
+    s->borderSettings = settings;
+    return *this;
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate(
         const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility,
         int8_t changeFrameRateStrategy) {
diff --git a/libs/gui/android/gui/BorderSettings.aidl b/libs/gui/android/gui/BorderSettings.aidl
new file mode 100644
index 0000000..547f57f
--- /dev/null
+++ b/libs/gui/android/gui/BorderSettings.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2025, 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 android.gui;
+
+/** @hide */
+parcelable BorderSettings {
+    float strokeWidth;
+    // Space is sRGB, not premultiplied, bit pattern is 0xAARRGGBB.
+    int color;
+}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 369d3d1..e2d27ac 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <span>
 
+#include <android/gui/BorderSettings.h>
 #include <android/gui/DisplayCaptureArgs.h>
 #include <android/gui/IWindowInfosReportedListener.h>
 #include <android/gui/LayerCaptureArgs.h>
@@ -250,6 +251,7 @@
         ePictureProfileHandleChanged = 0x80000'00000000,
         eAppContentPriorityChanged = 0x100000'00000000,
         eClientDrawnCornerRadiusChanged = 0x200000'00000000,
+        eBorderSettingsChanged = 0x400000'00000000,
     };
 
     layer_state_t();
@@ -293,8 +295,8 @@
             layer_state_t::eColorSpaceAgnosticChanged | layer_state_t::eColorTransformChanged |
             layer_state_t::eCornerRadiusChanged | layer_state_t::eDimmingEnabledChanged |
             layer_state_t::eHdrMetadataChanged | layer_state_t::eShadowRadiusChanged |
-            layer_state_t::eStretchChanged |
-            layer_state_t::ePictureProfileHandleChanged | layer_state_t::eAppContentPriorityChanged;
+            layer_state_t::eStretchChanged | layer_state_t::ePictureProfileHandleChanged |
+            layer_state_t::eAppContentPriorityChanged | layer_state_t::eBorderSettingsChanged;
 
     // Changes which invalidates the layer's visible region in CE.
     static constexpr uint64_t CONTENT_DIRTY = layer_state_t::CONTENT_CHANGES |
@@ -322,7 +324,8 @@
     // Changes that force GPU composition.
     static constexpr uint64_t COMPOSITION_EFFECTS = layer_state_t::eBackgroundBlurRadiusChanged |
             layer_state_t::eBlurRegionsChanged | layer_state_t::eCornerRadiusChanged |
-            layer_state_t::eShadowRadiusChanged | layer_state_t::eStretchChanged;
+            layer_state_t::eShadowRadiusChanged | layer_state_t::eStretchChanged |
+            layer_state_t::eBorderSettingsChanged;
 
     bool hasValidBuffer() const;
     void sanitize(int32_t permissions);
@@ -411,6 +414,9 @@
     // Draws a shadow around the surface.
     float shadowRadius;
 
+    // Draws an outline around the layer.
+    gui::BorderSettings borderSettings;
+
     // Priority of the layer assigned by Window Manager.
     int32_t frameRateSelectionPriority;
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 4fda8de..1ad9f95 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -717,6 +717,8 @@
                 const Rect& source, const Rect& dst, int transform);
         Transaction& setShadowRadius(const sp<SurfaceControl>& sc, float cornerRadius);
 
+        Transaction& setBorderSettings(const sp<SurfaceControl>& sc, gui::BorderSettings settings);
+
         Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate,
                                   int8_t compatibility, int8_t changeFrameRateStrategy);