Support Color and ColorSpace on Ravenwood

- Moved Color's JNI methods out of Shader.cpp, so Ravenwood
    can enable it without enabling other shader native methods.

- Also, leaned up the Matrix native methods while I'm here.

Bug: 337110712
Test: atest CtsGraphicsTestCases
Test: atest CtsGraphicsTestCasesRavenwood
Test: Boot the device
Change-Id: I0e99fb56ef581b4f59944994d07fd5253208dc31
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 0f2f879..c1edafc 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -289,6 +289,9 @@
  */
 @AnyThread
 @SuppressAutoDoc
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+        android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
 public class Color {
     @ColorInt public static final int BLACK       = 0xFF000000;
     @ColorInt public static final int DKGRAY      = 0xFF444444;
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index a2319a5..9284c0e 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -135,6 +135,9 @@
 @AnyThread
 @SuppressWarnings("StaticInitializerReferencesSubClass")
 @SuppressAutoDoc
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+        android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
 public abstract class ColorSpace {
     /**
      * Standard CIE 1931 2° illuminant A, encoded in xyY.
@@ -2490,9 +2493,12 @@
             return mNativePtr;
         }
 
-        private static native long nativeGetNativeFinalizer();
-        private static native long nativeCreate(float a, float b, float c, float d,
-                float e, float f, float g, float[] xyz);
+        /** Need a nested class due to b/337329128. */
+        static class Native {
+            static native long nativeGetNativeFinalizer();
+            static native long nativeCreate(float a, float b, float c, float d,
+                    float e, float f, float g, float[] xyz);
+        }
 
         private static DoubleUnaryOperator generateOETF(TransferParameters function) {
             if (function.isHLGish()) {
@@ -2959,7 +2965,7 @@
 
                 // This mimics the old code that was in native.
                 float[] nativeTransform = adaptToIlluminantD50(mWhitePoint, mTransform);
-                mNativePtr = nativeCreate((float) mTransferParameters.a,
+                mNativePtr = Native.nativeCreate((float) mTransferParameters.a,
                                           (float) mTransferParameters.b,
                                           (float) mTransferParameters.c,
                                           (float) mTransferParameters.d,
@@ -2975,7 +2981,7 @@
 
         private static class NoImagePreloadHolder {
             public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                ColorSpace.Rgb.class.getClassLoader(), nativeGetNativeFinalizer(), 0);
+                ColorSpace.Rgb.class.getClassLoader(), Native.nativeGetNativeFinalizer(), 0);
         }
 
         /**
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index fbb690c..ebf90bc 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -232,7 +232,7 @@
     private static class NoImagePreloadHolder {
         public static final NativeAllocationRegistry sRegistry =
                 NativeAllocationRegistry.createMalloced(
-                Matrix.class.getClassLoader(), nGetNativeFinalizerWrapper());
+                Matrix.class.getClassLoader(), ExtraNatives.nGetNativeFinalizer());
     }
 
     private final long native_instance;
@@ -241,7 +241,7 @@
      * Create an identity matrix
      */
     public Matrix() {
-        native_instance = nCreateWrapper(0);
+        native_instance = ExtraNatives.nCreate(0);
         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
     }
 
@@ -251,7 +251,7 @@
      * @param src The matrix to copy into this matrix
      */
     public Matrix(Matrix src) {
-        native_instance = nCreateWrapper(src != null ? src.native_instance : 0);
+        native_instance = ExtraNatives.nCreate(src != null ? src.native_instance : 0);
         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
     }
 
@@ -849,40 +849,6 @@
         return native_instance;
     }
 
-    /**
-     * Wrapper method we use to switch to ExtraNatives.nCreate(src) only on Ravenwood.
-     *
-     * @see ExtraNatives
-     */
-    @android.ravenwood.annotation.RavenwoodReplace
-    private static long nCreateWrapper(long src) {
-        return nCreate(src);
-    }
-
-    private static long nCreateWrapper$ravenwood(long src) {
-        return ExtraNatives.nCreate(src);
-    }
-
-    /**
-     * Wrapper method we use to switch to ExtraNatives.nGetNativeFinalizer(src) only on Ravenwood.
-     *
-     * @see ExtraNatives
-     */
-    @android.ravenwood.annotation.RavenwoodReplace
-    private static long nGetNativeFinalizerWrapper() {
-        return nGetNativeFinalizer();
-    }
-
-    private static long nGetNativeFinalizerWrapper$ravenwood() {
-        return ExtraNatives.nGetNativeFinalizer();
-    }
-
-    // ------------------ Regular JNI ------------------------
-
-    private static native long nCreate(long nSrc_or_zero);
-    private static native long nGetNativeFinalizer();
-
-
     // ------------------ Fast JNI ------------------------
 
     @FastNative
@@ -982,14 +948,6 @@
      * There are two methods that are called by the static initializers (either directly or
      * indirectly) in this class, namely nCreate() and nGetNativeFinalizer(). On Ravenwood
      * these methods can't be on the Matrix class itself, so we use a nested class to host them.
-     *
-     * We still keep the original nCreate() method and call it on non-ravenwood environment,
-     * in order to avoid problems in downstream (such as Android Studio).
-     *
-     * @see #nCreateWrapper(long)
-     * @see #nGetNativeFinalizerWrapper()
-     *
-     * TODO(b/337110712) Clean it up somehow. (remove the original nCreate() and unify the code?)
      */
     private static class ExtraNatives {
         static native long nCreate(long nSrc_or_zero);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 753a699..7c1c5b4 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -336,6 +336,7 @@
         "jni/android_graphics_animation_NativeInterpolatorFactory.cpp",
         "jni/android_graphics_animation_RenderNodeAnimator.cpp",
         "jni/android_graphics_Canvas.cpp",
+        "jni/android_graphics_Color.cpp",
         "jni/android_graphics_ColorSpace.cpp",
         "jni/android_graphics_drawable_AnimatedVectorDrawable.cpp",
         "jni/android_graphics_drawable_VectorDrawable.cpp",
diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp
index fd9915a..70a9ef0 100644
--- a/libs/hwui/apex/LayoutlibLoader.cpp
+++ b/libs/hwui/apex/LayoutlibLoader.cpp
@@ -46,6 +46,7 @@
 
 extern int register_android_graphics_Canvas(JNIEnv* env);
 extern int register_android_graphics_CanvasProperty(JNIEnv* env);
+extern int register_android_graphics_Color(JNIEnv* env);
 extern int register_android_graphics_ColorFilter(JNIEnv* env);
 extern int register_android_graphics_ColorSpace(JNIEnv* env);
 extern int register_android_graphics_DrawFilter(JNIEnv* env);
@@ -87,6 +88,7 @@
         {"android.graphics.Camera", REG_JNI(register_android_graphics_Camera)},
         {"android.graphics.Canvas", REG_JNI(register_android_graphics_Canvas)},
         {"android.graphics.CanvasProperty", REG_JNI(register_android_graphics_CanvasProperty)},
+        {"android.graphics.Color", REG_JNI(register_android_graphics_Color)},
         {"android.graphics.ColorFilter", REG_JNI(register_android_graphics_ColorFilter)},
         {"android.graphics.ColorSpace", REG_JNI(register_android_graphics_ColorSpace)},
         {"android.graphics.CreateJavaOutputStreamAdaptor",
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index fb0cdb0..6ace396 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -49,6 +49,7 @@
 extern int register_android_graphics_Canvas(JNIEnv* env);
 extern int register_android_graphics_CanvasProperty(JNIEnv* env);
 extern int register_android_graphics_ColorFilter(JNIEnv* env);
+extern int register_android_graphics_Color(JNIEnv* env);
 extern int register_android_graphics_ColorSpace(JNIEnv* env);
 extern int register_android_graphics_DrawFilter(JNIEnv* env);
 extern int register_android_graphics_FontFamily(JNIEnv* env);
@@ -98,6 +99,7 @@
 
     static const RegJNIRec gRegJNI[] = {
             REG_JNI(register_android_graphics_Canvas),
+            REG_JNI(register_android_graphics_Color),
             // This needs to be before register_android_graphics_Graphics, or the latter
             // will not be able to find the jmethodID for ColorSpace.get().
             REG_JNI(register_android_graphics_ColorSpace),
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index a952be0..2a057e7 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -36,25 +36,6 @@
         return 0;                   \
     }
 
-static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue, jfloatArray hsvArray)
-{
-    SkScalar hsv[3];
-    SkRGBToHSV(red, green, blue, hsv);
-
-    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
-    float* values = autoHSV.ptr();
-    for (int i = 0; i < 3; i++) {
-        values[i] = SkScalarToFloat(hsv[i]);
-    }
-}
-
-static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
-{
-    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
-    SkScalar* hsv = autoHSV.ptr();
-    return static_cast<jint>(SkHSVToColor(alpha, hsv));
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 static void Shader_safeUnref(SkShader* shader) {
@@ -409,11 +390,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static const JNINativeMethod gColorMethods[] = {
-    { "nativeRGBToHSV",    "(III[F)V", (void*)Color_RGBToHSV   },
-    { "nativeHSVToColor",  "(I[F)I",   (void*)Color_HSVToColor }
-};
-
 static const JNINativeMethod gShaderMethods[] = {
     { "nativeGetFinalizer",   "()J",    (void*)Shader_getNativeFinalizer },
 };
@@ -456,8 +432,6 @@
 
 int register_android_graphics_Shader(JNIEnv* env)
 {
-    android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
-                                  NELEM(gColorMethods));
     android::RegisterMethodsOrDie(env, "android/graphics/Shader", gShaderMethods,
                                   NELEM(gShaderMethods));
     android::RegisterMethodsOrDie(env, "android/graphics/BitmapShader", gBitmapShaderMethods,
diff --git a/libs/hwui/jni/android_graphics_Color.cpp b/libs/hwui/jni/android_graphics_Color.cpp
new file mode 100644
index 0000000..c22b8b9
--- /dev/null
+++ b/libs/hwui/jni/android_graphics_Color.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include "GraphicsJNI.h"
+
+#include "SkColor.h"
+
+using namespace android;
+
+static void Color_RGBToHSV(JNIEnv* env, jobject, jint red, jint green, jint blue,
+                           jfloatArray hsvArray)
+{
+    SkScalar hsv[3];
+    SkRGBToHSV(red, green, blue, hsv);
+
+    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
+    float* values = autoHSV.ptr();
+    for (int i = 0; i < 3; i++) {
+        values[i] = SkScalarToFloat(hsv[i]);
+    }
+}
+
+static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvArray)
+{
+    AutoJavaFloatArray  autoHSV(env, hsvArray, 3);
+    SkScalar* hsv = autoHSV.ptr();
+    return static_cast<jint>(SkHSVToColor(alpha, hsv));
+}
+
+static const JNINativeMethod gColorMethods[] = {
+    { "nativeRGBToHSV",    "(III[F)V", (void*)Color_RGBToHSV   },
+    { "nativeHSVToColor",  "(I[F)I",   (void*)Color_HSVToColor }
+};
+
+namespace android {
+
+int register_android_graphics_Color(JNIEnv* env) {
+    return android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
+                                         NELEM(gColorMethods));
+}
+
+}; // namespace android
diff --git a/libs/hwui/jni/android_graphics_ColorSpace.cpp b/libs/hwui/jni/android_graphics_ColorSpace.cpp
index 63d3f83..d06206b 100644
--- a/libs/hwui/jni/android_graphics_ColorSpace.cpp
+++ b/libs/hwui/jni/android_graphics_ColorSpace.cpp
@@ -148,7 +148,7 @@
 namespace android {
 
 int register_android_graphics_ColorSpace(JNIEnv* env) {
-    return android::RegisterMethodsOrDie(env, "android/graphics/ColorSpace$Rgb",
+    return android::RegisterMethodsOrDie(env, "android/graphics/ColorSpace$Rgb$Native",
                                          gColorSpaceRgbMethods, NELEM(gColorSpaceRgbMethods));
 }
 
diff --git a/libs/hwui/jni/android_graphics_Matrix.cpp b/libs/hwui/jni/android_graphics_Matrix.cpp
index c0d791a..eedc069 100644
--- a/libs/hwui/jni/android_graphics_Matrix.cpp
+++ b/libs/hwui/jni/android_graphics_Matrix.cpp
@@ -326,9 +326,6 @@
 };
 
 static const JNINativeMethod methods[] = {
-    {"nGetNativeFinalizer", "()J", (void*) SkMatrixGlue::getNativeFinalizer},
-    {"nCreate","(J)J", (void*) SkMatrixGlue::create},
-
     // ------- @FastNative below here ---------------
     {"nMapPoints","(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
     {"nMapRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z",
@@ -388,9 +385,6 @@
 int register_android_graphics_Matrix(JNIEnv* env) {
     // Methods only used on Ravenwood (for now). See the javadoc on Matrix$ExtraNativesx
     // for why we need it.
-    //
-    // We don't need it on non-ravenwood, but we don't (yet) have a way to detect ravenwood
-    // environment, so we just always run it.
     RegisterMethodsOrDie(env, "android/graphics/Matrix$ExtraNatives", extra_methods,
                          NELEM(extra_methods));
 
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
index 96b7057..69ff262 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
@@ -162,20 +162,23 @@
             android.graphics.Interpolator.class,
             android.graphics.Matrix.class,
             android.graphics.Path.class,
+            android.graphics.Color.class,
+            android.graphics.ColorSpace.class,
     };
 
     /**
-     * @return if a given class has any native method or not.
+     * @return if a given class and its nested classes, if any, have any native method or not.
      */
     private static boolean hasNativeMethod(Class<?> clazz) {
-        for (var method : clazz.getDeclaredMethods()) {
-            if (Modifier.isNative(method.getModifiers())) {
-                return true;
+        for (var nestedClass : clazz.getNestMembers()) {
+            for (var method : nestedClass.getDeclaredMethods()) {
+                if (Modifier.isNative(method.getModifiers())) {
+                    return true;
+                }
             }
         }
         return false;
     }
-
     /**
      * Create a list of classes as comma-separated that require JNI methods to be set up from
      * a given class list, ignoring classes with no native methods.
diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
index e452299..364ea7f 100644
--- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
@@ -237,6 +237,8 @@
 android.accounts.Account
 
 android.graphics.Bitmap$Config
+android.graphics.Color
+android.graphics.ColorSpace
 android.graphics.Insets
 android.graphics.Interpolator
 android.graphics.Matrix