[Shadows] Populate global shadow settings (3/n)

Read framework resources and call the new SurfaceControl#setGlobalShadowSettings
API to set global shadow settings. Some of these settings can be overrided by
apps but for shadows drawn by SurfaceFlinger to be applied on surfaces, as opposed
to app content, we will keep all settings constant.

Bug: 136561771
Test: go/wm-smoke
Change-Id: I6f759479352e6923b883cae67f9b089d82978d30
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 3251127..6458737 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -199,6 +199,8 @@
     private static native void nativeWriteTransactionToParcel(long nativeObject, Parcel out);
     private static native void nativeSetShadowRadius(long transactionObj, long nativeObject,
             float shadowRadius);
+    private static native void nativeSetGlobalShadowSettings(@Size(4) float[] ambientColor,
+            @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius);
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private String mName;
@@ -1979,6 +1981,42 @@
         return sc;
     }
 
+    private static void validateColorArg(@Size(4) float[] color) {
+        final String msg = "Color must be specified as a float array with"
+                + " four values to represent r, g, b, a in range [0..1]";
+        if (color.length != 4) {
+            throw new IllegalArgumentException(msg);
+        }
+        for (float c:color) {
+            if ((c < 0.f) || (c > 1.f)) {
+                throw new IllegalArgumentException(msg);
+            }
+        }
+    }
+
+    /**
+     * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
+     * material design guidelines.
+     *
+     * @param ambientColor Color applied to the ambient shadow. The alpha is premultiplied. A
+     *                     float array with four values to represent r, g, b, a in range [0..1]
+     * @param spotColor Color applied to the spot shadow. The alpha is premultiplied. The position
+     *                  of the spot shadow depends on the light position. A float array with
+     *                  four values to represent r, g, b, a in range [0..1]
+     * @param lightPosY Y axis position of the light used to cast the spot shadow in pixels.
+     * @param lightPosZ Z axis position of the light used to cast the spot shadow in pixels. The X
+     *                  axis position is set to the display width / 2.
+     * @param lightRadius Radius of the light casting the shadow in pixels.
+     *[
+     * @hide
+     */
+    public static void setGlobalShadowSettings(@Size(4) float[] ambientColor,
+            @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius) {
+        validateColorArg(ambientColor);
+        validateColorArg(spotColor);
+        nativeSetGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius);
+    }
+
      /**
      * An atomic set of changes to a set of SurfaceControl.
      */
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index f8a2744..9f20388 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -491,6 +491,7 @@
     float* floatColors = env->GetFloatArrayElements(fColor, 0);
     half3 color(floatColors[0], floatColors[1], floatColors[2]);
     transaction->setColor(ctrl, color);
+    env->ReleaseFloatArrayElements(fColor, floatColors, 0);
 }
 
 static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -508,8 +509,12 @@
     SurfaceControl* const surfaceControl = reinterpret_cast<SurfaceControl*>(nativeObject);
     float* floatMatrix = env->GetFloatArrayElements(fMatrix, 0);
     mat3 matrix(static_cast<float const*>(floatMatrix));
+    env->ReleaseFloatArrayElements(fMatrix, floatMatrix, 0);
+
     float* floatTranslation = env->GetFloatArrayElements(fTranslation, 0);
     vec3 translation(floatTranslation[0], floatTranslation[1], floatTranslation[2]);
+    env->ReleaseFloatArrayElements(fTranslation, floatTranslation, 0);
+
     transaction->setColorTransform(surfaceControl, matrix, translation);
 }
 
@@ -1262,6 +1267,22 @@
     return reinterpret_cast<jlong>(surface.get());
 }
 
+static void nativeSetGlobalShadowSettings(JNIEnv* env, jclass clazz, jfloatArray jAmbientColor,
+        jfloatArray jSpotColor, jfloat lightPosY, jfloat lightPosZ, jfloat lightRadius) {
+    sp<SurfaceComposerClient> client = SurfaceComposerClient::getDefault();
+
+    float* floatAmbientColor = env->GetFloatArrayElements(jAmbientColor, 0);
+    half4 ambientColor = half4(floatAmbientColor[0], floatAmbientColor[1], floatAmbientColor[2],
+            floatAmbientColor[3]);
+    env->ReleaseFloatArrayElements(jAmbientColor, floatAmbientColor, 0);
+
+    float* floatSpotColor = env->GetFloatArrayElements(jSpotColor, 0);
+    half4 spotColor = half4(floatSpotColor[0], floatSpotColor[1], floatSpotColor[2],
+            floatSpotColor[3]);
+    env->ReleaseFloatArrayElements(jSpotColor, floatSpotColor, 0);
+
+    client->setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius);
+}
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod sSurfaceControlMethods[] = {
@@ -1416,6 +1437,8 @@
             (void*)nativeWriteTransactionToParcel },
     {"nativeMirrorSurface", "(J)J",
             (void*)nativeMirrorSurface },
+    {"nativeSetGlobalShadowSettings", "([F[FFFF)V",
+            (void*)nativeSetGlobalShadowSettings },
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 519cc21..560d377 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -146,6 +146,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.res.Configuration;
+import android.content.res.TypedArray;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
@@ -1296,6 +1297,20 @@
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
         mEmbeddedWindowController = new EmbeddedWindowController(mGlobalLock);
+        setGlobalShadowSettings();
+    }
+
+    private void setGlobalShadowSettings() {
+        final TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
+        float lightY = a.getDimension(R.styleable.Lighting_lightY, 0);
+        float lightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
+        float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
+        float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);
+        float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);
+        float[] ambientColor = {0.f, 0.f, 0.f, ambientShadowAlpha};
+        float[] spotColor = {0.f, 0.f, 0.f, spotShadowAlpha};
+        SurfaceControl.setGlobalShadowSettings(ambientColor, spotColor, lightY, lightZ,
+                lightRadius);
     }
 
     /**