1 /*
<lambda>null2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package platform.test.screenshot
18 
19 import android.content.Context
20 import android.util.Log
21 import android.util.SparseIntArray
22 import android.widget.RemoteViews
23 import androidx.annotation.VisibleForTesting
24 import androidx.test.platform.app.InstrumentationRegistry
25 import org.junit.rules.TestRule
26 import org.junit.runner.Description
27 import org.junit.runners.model.Statement
28 
29 /**
30  * A rule to overload the target context system colors by [colors].
31  *
32  * This is especially useful to apply the colors before you start an activity using an
33  * [ActivityScenarioRule] or any other rule, given that the colors must be [applied]
34  * [MaterialYouColors.apply] *before* doing any resource resolution.
35  */
36 class MaterialYouColorsRule(private val colors: MaterialYouColors = MaterialYouColors.GreenBlue) :
37     TestRule {
38     override fun apply(base: Statement, description: Description): Statement {
39         return object : Statement() {
40             override fun evaluate() {
41                 colors.apply(InstrumentationRegistry.getInstrumentation().targetContext)
42                 base.evaluate()
43             }
44         }
45     }
46 }
47 
48 /**
49  * A util class to overload the Material You colors of a [Context] to some fixed values. This can be
50  * used by screenshot tests so that device-specific colors don't impact the outcome of the test.
51  *
52  * @see apply
53  */
54 class MaterialYouColors(
55     @get:VisibleForTesting val colors: SparseIntArray,
56 ) {
57     /**
58      * Apply these colors to [context].
59      *
60      * Important: No resource resolution must have be done on the context given to that method.
61      */
applynull62     fun apply(context: Context) {
63         RemoteViews.ColorResources.create(context, colors)?.apply(context)
64     }
65 
66     companion object {
67         private const val FIRST_RESOURCE_COLOR_ID = android.R.color.system_neutral1_0
68         private const val LAST_RESOURCE_COLOR_ID = android.R.color.system_error_1000
69 
70         /**
71          * An instance of [MaterialYouColors] with green/blue colors seed, that can be used directly
72          * by tests.
73          */
74         val GreenBlue = fromColors(GREEN_BLUE)
75 
76         /**
77          * Create a [MaterialYouColors] from [colors], where:
78          * - `colors[i]` should be the value of `FIRST_RESOURCE_COLOR_ID + i`.
79          * - [colors] are recommended to contain all values of all system colors, i.e. `colors.size`
80          *   is best to be `LAST_RESOURCE_COLOR_ID - FIRST_RESOURCE_COLOR_ID + 1`, otherwise we are
81          *   expected to observed unused values in the sparse array (more elements in the array) or
82          *   unconfigured system colors (fewer elements in the array).
83          */
fromColorsnull84         private fun fromColors(colors: IntArray): MaterialYouColors {
85             val expectedSize = LAST_RESOURCE_COLOR_ID - FIRST_RESOURCE_COLOR_ID + 1
86             if (colors.size != expectedSize) {
87                 Log.d(
88                     "MaterialYouColors.fromColors",
89                     "colors are best to have exactly $expectedSize elements for a complete " +
90                     "configuration for system colors")
91             }
92 
93             val sparseArray = SparseIntArray(/* initialCapacity= */ expectedSize)
94             colors.forEachIndexed { i, color ->
95                 sparseArray.put(FIRST_RESOURCE_COLOR_ID + i, color)
96             }
97 
98             return MaterialYouColors(sparseArray)
99         }
100     }
101 }
102 
103 /**
104  * Some green/blue colors, from system_neutral1_0 to system_accent3_1000, extracted using 0xB1EBFF
105  * as seed color and "FRUIT_SALAD" as theme style.
106  */
107 private val GREEN_BLUE =
108     intArrayOf(
109         -1,
110         -393729,
111         -1641480,
112         -2562838,
113         -4405043,
114         -6181454,
115         -7892073,
116         -9668483,
117         -11181979,
118         -12760755,
119         -14208458,
120         -15590111,
121         -16777216,
122         -1,
123         -393729,
124         -2296322,
125         -3217680,
126         -4994349,
127         -6770760,
128         -8547171,
129         -10257790,
130         -11836822,
131         -13350318,
132         -14863301,
133         -16376283,
134         -16777216,
135         -1,
136         -720905,
137         -4456478,
138         -8128307,
139         -10036302,
140         -12075112,
141         -14638210,
142         -16742810,
143         -16749487,
144         -16756420,
145         -16762839,
146         -16768746,
147         -16777216,
148         -1,
149         -720905,
150         -4456478,
151         -5901613,
152         -7678281,
153         -9454947,
154         -11231613,
155         -13139095,
156         -15111342,
157         -16756420,
158         -16762839,
159         -16768746,
160         -16777216,
161         -1,
162         -393729,
163         -2361857,
164         -5051393,
165         -7941655,
166         -9783603,
167         -11625551,
168         -13729642,
169         -16750723,
170         -16757153,
171         -16763326,
172         -16769241,
173         -16777216,
174   /* "system_primary_container_light" */ -2432257,
175   /* "system_on_primary_container_light" */ -16770999,
176   /* "system_primary_light" */ -11969134,
177   /* "system_on_primary_light" */ -1,
178   /* "system_secondary_container_light" */ -2235655,
179   /* "system_on_secondary_container_light" */ -15394004,
180   /* "system_secondary_light" */ -10985871,
181   /* "system_on_secondary_light" */ -1,
182   /* "system_tertiary_container_light" */ -76039,
183   /* "system_on_tertiary_container_light" */ -13954517,
184   /* "system_tertiary_light" */ -9218959,
185   /* "system_on_tertiary_light" */ -1,
186   /* "system_background_light" */ -329473,
187   /* "system_on_background_light" */ -15066335,
188   /* "system_surface_light" */ -329473,
189   /* "system_on_surface_light" */ -15066335,
190   /* "system_surface_container_low_light" */ -723974,
191   /* "system_surface_container_lowest_light" */ -1,
192   /* "system_surface_container_light" */ -1118732,
193   /* "system_surface_container_high_light" */ -1513489,
194   /* "system_surface_container_highest_light" */ -1842455,
195   /* "system_surface_bright_light" */ -329473,
196   /* "system_surface_dim_light" */ -2434592,
197   /* "system_surface_variant_light" */ -1973524,
198   /* "system_on_surface_variant_light" */ -12237233,
199   /* "system_outline_light" */ -9078912,
200   /* "system_error_light" */ -4580838,
201   /* "system_on_error_light" */ -1,
202   /* "system_error_container_light" */ -9514,
203   /* "system_on_error_container_light" */ -12517374,
204   /* "system_control_activated_light" */ -2432257,
205   /* "system_control_normal_light" */ -12237233,
206   /* "system_control_highlight_light" */ 520093696,
207   /* "system_text_primary_inverse_light" */ -1842455,
208   /* "system_text_secondary_and_tertiary_inverse_light" */ -3815728,
209   /* "system_text_primary_inverse_disable_only_light" */ -1842455,
210   /* "system_text_secondary_and_tertiary_inverse_disabled_light" */ -1842455,
211   /* "system_text_hint_inverse_light" */ -1842455,
212   /* "system_palette_key_color_primary_light" */ -10324564,
213   /* "system_palette_key_color_secondary_light" */ -9341301,
214   /* "system_palette_key_color_tertiary_light" */ -7443061,
215   /* "system_palette_key_color_neutral_light" */ -9013379,
216   /* "system_palette_key_color_neutral_variant_light" */ -9013376,
217   /* "system_primary_container_dark" */ -13548168,
218   /* "system_on_primary_container_dark" */ -2432257,
219   /* "system_primary_dark" */ -5061121,
220   /* "system_on_primary_dark" */ -15192480,
221   /* "system_secondary_container_dark" */ -12499367,
222   /* "system_on_secondary_container_dark" */ -2235655,
223   /* "system_secondary_dark" */ -4143395,
224   /* "system_on_secondary_dark" */ -14012350,
225   /* "system_tertiary_container_dark" */ -10863271,
226   /* "system_on_tertiary_container_dark" */ -76039,
227   /* "system_tertiary_dark" */ -1983524,
228   /* "system_on_tertiary_dark" */ -12441791,
229   /* "system_background_dark" */ -15592680,
230   /* "system_on_background_dark" */ -1842455,
231   /* "system_surface_dark" */ -15592680,
232   /* "system_on_surface_dark" */ -1842455,
233   /* "system_surface_container_low_dark" */ -15066335,
234   /* "system_surface_container_lowest_dark" */ -15921645,
235   /* "system_surface_container_dark" */ -14803163,
236   /* "system_surface_container_high_dark" */ -14079441,
237   /* "system_surface_container_highest_dark" */ -13421510,
238   /* "system_surface_bright_dark" */ -13092545,
239   /* "system_surface_dim_dark" */ -15592680,
240   /* "system_surface_variant_dark" */ -12237233,
241   /* "system_on_surface_variant_dark" */ -3815728,
242   /* "system_outline_dark" */ -7368550,
243   /* "system_error_dark" */ -19285,
244   /* "system_on_error_dark" */ -9895931,
245   /* "system_error_container_dark" */ -7143414,
246   /* "system_on_error_container_dark" */ -9514,
247   /* "system_control_activated_dark" */ -13548168,
248   /* "system_control_normal_dark" */ -3815728,
249   /* "system_control_highlight_dark" */ 872415231,
250   /* "system_text_primary_inverse_dark" */ -15066335,
251   /* "system_text_secondary_and_tertiary_inverse_dark" */ -12237233,
252   /* "system_text_primary_inverse_disable_only_dark" */ -15066335,
253   /* "system_text_secondary_and_tertiary_inverse_disabled_dark" */ -15066335,
254   /* "system_text_hint_inverse_dark" */ -15066335,
255   /* "system_palette_key_color_primary_dark" */ -10324564,
256   /* "system_palette_key_color_secondary_dark" */ -9341301,
257   /* "system_palette_key_color_tertiary_dark" */ -7443061,
258   /* "system_palette_key_color_neutral_dark" */ -9013379,
259   /* "system_palette_key_color_neutral_variant_dark" */ -9013376,
260   /* "system_primary_fixed" */ -2432257,
261   /* "system_primary_fixed_dim" */ -5061121,
262   /* "system_on_primary_fixed" */ -16770999,
263   /* "system_on_primary_fixed_variant" */ -13548168,
264   /* "system_secondary_fixed" */ -2235655,
265   /* "system_secondary_fixed_dim" */ -4143395,
266   /* "system_on_secondary_fixed" */ -15394004,
267   /* "system_on_secondary_fixed_variant" */ -12499367,
268   /* "system_tertiary_fixed" */ -76039,
269   /* "system_tertiary_fixed_dim" */ -1983524,
270   /* "system_on_tertiary_fixed" */ -13954517,
271   /* "system_on_tertiary_fixed_variant" */ -10863271,
272   /* "system_outline_variant_light" */ -3815728,
273   /* "system_outline_variant_dark" */ -12237233,
274   /* "system_surface_disabled" */ 1123743999,
275   /* "system_on_surface_disabled" */ 1109007137,
276   /* "system_outline_disabled" */ 1114994560,
277   /* "system_error_0" */ -1,
278   /* "system_error_10" */ -1031,
279   /* "system_error_50" */ -200978,
280   /* "system_error_100" */ -401700,
281   /* "system_error_200" */ -870219,
282   /* "system_error_300" */ -1273202,
283   /* "system_error_400" */ -1808030,
284   /* "system_error_500" */ -2345426,
285   /* "system_error_600" */ -5036514,
286   /* "system_error_700" */ -7594728,
287   /* "system_error_800" */ -10480624,
288   /* "system_error_900" */ -12513781,
289   /* "system_error_1000" */ -16777216,
290     )
291