9
9
10
10
import android .content .Context ;
11
11
import android .content .res .Resources ;
12
+ import android .graphics .Color ;
13
+ import android .graphics .ColorSpace ;
14
+ import android .os .Build ;
12
15
import android .util .TypedValue ;
16
+ import androidx .annotation .ColorLong ;
13
17
import androidx .annotation .Nullable ;
14
18
import androidx .core .content .res .ResourcesCompat ;
15
19
import com .facebook .common .logging .FLog ;
16
20
import com .facebook .react .common .ReactConstants ;
17
21
18
22
public class ColorPropConverter {
23
+
24
+ private static Boolean supportWideGamut () {
25
+ return Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ;
26
+ }
27
+
19
28
private static final String JSON_KEY = "resource_paths" ;
20
29
private static final String PREFIX_RESOURCE = "@" ;
21
30
private static final String PREFIX_ATTR = "?" ;
@@ -24,7 +33,7 @@ public class ColorPropConverter {
24
33
private static final String ATTR = "attr" ;
25
34
private static final String ATTR_SEGMENT = "attr/" ;
26
35
27
- public static Integer getColor (Object value , Context context ) {
36
+ private static Integer getColorInteger (Object value , Context context ) {
28
37
if (value == null ) {
29
38
return null ;
30
39
}
@@ -33,18 +42,13 @@ public static Integer getColor(Object value, Context context) {
33
42
return ((Double ) value ).intValue ();
34
43
}
35
44
36
- if (context == null ) {
37
- throw new RuntimeException ("Context may not be null." );
38
- }
45
+ throwIfNullContext (context );
39
46
40
47
if (value instanceof ReadableMap ) {
41
48
ReadableMap map = (ReadableMap ) value ;
42
49
ReadableArray resourcePaths = map .getArray (JSON_KEY );
43
50
44
- if (resourcePaths == null ) {
45
- throw new JSApplicationCausedNativeException (
46
- "ColorValue: The `" + JSON_KEY + "` must be an array of color resource path strings." );
47
- }
51
+ throwIfNullResourcePaths (resourcePaths );
48
52
49
53
for (int i = 0 ; i < resourcePaths .size (); i ++) {
50
54
Integer result = resolveResourcePath (context , resourcePaths .getString (i ));
@@ -53,16 +57,62 @@ public static Integer getColor(Object value, Context context) {
53
57
}
54
58
}
55
59
56
- throw new JSApplicationCausedNativeException (
57
- "ColorValue: None of the paths in the `"
58
- + JSON_KEY
59
- + "` array resolved to a color resource." );
60
+ throwColorResourceNotFound ();
61
+ }
62
+
63
+ throw new JSApplicationCausedNativeException (
64
+ "ColorValue: the value must be a number or Object." );
65
+ }
66
+
67
+ public static Color getColorInstance (Object value , Context context ) {
68
+ if (value == null ) {
69
+ return null ;
60
70
}
61
71
72
+ if (supportWideGamut () && value instanceof Double ) {
73
+ return Color .valueOf (((Double ) value ).intValue ());
74
+ }
75
+
76
+ throwIfNullContext (context );
77
+
78
+ if (value instanceof ReadableMap ) {
79
+ ReadableMap map = (ReadableMap ) value ;
80
+
81
+ Color wideGamutColor = extractWideGamutColorIfPossible (map );
82
+ if (wideGamutColor != null ) {
83
+ return wideGamutColor ;
84
+ }
85
+
86
+ ReadableArray resourcePaths = map .getArray (JSON_KEY );
87
+ throwIfNullResourcePaths (resourcePaths );
88
+
89
+ for (int i = 0 ; i < resourcePaths .size (); i ++) {
90
+ Integer result = resolveResourcePath (context , resourcePaths .getString (i ));
91
+ if (supportWideGamut () && result != null ) {
92
+ return Color .valueOf (result );
93
+ }
94
+ }
95
+
96
+ throwColorResourceNotFound ();
97
+ }
62
98
throw new JSApplicationCausedNativeException (
63
99
"ColorValue: the value must be a number or Object." );
64
100
}
65
101
102
+ public static Integer getColor (Object value , Context context ) {
103
+ try {
104
+ if (supportWideGamut ()) {
105
+ Color color = getColorInstance (value , context );
106
+ if (color != null ) {
107
+ return color .toArgb ();
108
+ }
109
+ }
110
+ } catch (JSApplicationCausedNativeException ex ) {
111
+ FLog .w (ReactConstants .TAG , ex , "Error extracting color from WideGamut" );
112
+ }
113
+ return getColorInteger (value , context );
114
+ }
115
+
66
116
public static Integer getColor (Object value , Context context , int defaultInt ) {
67
117
try {
68
118
return getColor (value , context );
@@ -139,4 +189,41 @@ private static int resolveThemeAttribute(Context context, String resourcePath) {
139
189
140
190
throw new Resources .NotFoundException ();
141
191
}
192
+
193
+ private static void throwIfNullContext (Context context ) {
194
+ if (context == null ) {
195
+ throw new RuntimeException ("Context may not be null." );
196
+ }
197
+ }
198
+
199
+ private static void throwIfNullResourcePaths (ReadableArray resourcePaths ) {
200
+ if (resourcePaths == null ) {
201
+ throw new JSApplicationCausedNativeException (
202
+ "ColorValue: The `" + JSON_KEY + "` must be an array of color resource path strings." );
203
+ }
204
+ }
205
+
206
+ private static void throwColorResourceNotFound () {
207
+ throw new JSApplicationCausedNativeException (
208
+ "ColorValue: None of the paths in the `"
209
+ + JSON_KEY
210
+ + "` array resolved to a color resource." );
211
+ }
212
+
213
+ private static Color extractWideGamutColorIfPossible (ReadableMap map ) {
214
+ if (supportWideGamut () && map .hasKey ("space" )) {
215
+ String rawColorSpace = map .getString ("space" );
216
+ boolean isDisplayP3 = rawColorSpace .equals ("display-p3" );
217
+ ColorSpace space =
218
+ ColorSpace .get (isDisplayP3 ? ColorSpace .Named .DISPLAY_P3 : ColorSpace .Named .SRGB );
219
+ float r = (float ) map .getDouble ("r" );
220
+ float g = (float ) map .getDouble ("g" );
221
+ float b = (float ) map .getDouble ("b" );
222
+ float a = (float ) map .getDouble ("a" );
223
+
224
+ @ ColorLong long color = Color .pack (r , g , b , a , space );
225
+ return Color .valueOf (color );
226
+ }
227
+ return null ;
228
+ }
142
229
}
0 commit comments