1 /* 2 * Copyright (C) 2008 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 package android.graphics.cts; 17 18 import static androidx.test.InstrumentationRegistry.getInstrumentation; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertTrue; 22 23 import android.content.res.Resources; 24 import android.graphics.Color; 25 import android.platform.test.annotations.DisabledOnRavenwood; 26 import android.platform.test.ravenwood.RavenwoodRule; 27 import android.util.ArraySet; 28 import android.util.Log; 29 import android.util.TypedValue; 30 31 import androidx.test.filters.SmallTest; 32 import androidx.test.runner.AndroidJUnit4; 33 34 import org.junit.Rule; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.lang.annotation.Annotation; 39 import java.lang.reflect.Field; 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.List; 43 import java.util.Set; 44 45 @SmallTest 46 @RunWith(AndroidJUnit4.class) 47 public class ColorTest { 48 49 private static final String LOG_TAG = ColorTest.class.getSimpleName(); 50 51 @Rule 52 public final RavenwoodRule mRavenwood = new RavenwoodRule(); 53 54 @Test 55 @DisabledOnRavenwood(blockedBy = Resources.class) resourceColor()56 public void resourceColor() { 57 int[][] colors = { 58 { 0xff000000, android.R.color.background_dark }, 59 { 0xffffffff, android.R.color.background_light }, 60 { 0xff000000, android.R.color.black }, 61 { 0xffaaaaaa, android.R.color.darker_gray }, 62 { 0xff00ddff, android.R.color.holo_blue_bright }, 63 { 0xff0099cc, android.R.color.holo_blue_dark }, 64 { 0xff33b5e5, android.R.color.holo_blue_light }, 65 { 0xff669900, android.R.color.holo_green_dark }, 66 { 0xff99cc00, android.R.color.holo_green_light }, 67 { 0xffff8800, android.R.color.holo_orange_dark }, 68 { 0xffffbb33, android.R.color.holo_orange_light }, 69 { 0xffaa66cc, android.R.color.holo_purple }, 70 { 0xffcc0000, android.R.color.holo_red_dark }, 71 { 0xffff4444, android.R.color.holo_red_light }, 72 { 0xffffffff, android.R.color.primary_text_dark }, 73 { 0xffffffff, android.R.color.primary_text_dark_nodisable }, 74 { 0xff000000, android.R.color.primary_text_light }, 75 { 0xff000000, android.R.color.primary_text_light_nodisable }, 76 { 0xffbebebe, android.R.color.secondary_text_dark }, 77 { 0xffbebebe, android.R.color.secondary_text_dark_nodisable }, 78 { 0xff323232, android.R.color.secondary_text_light }, 79 { 0xffbebebe, android.R.color.secondary_text_light_nodisable }, 80 { 0xff808080, android.R.color.tab_indicator_text }, 81 { 0xff808080, android.R.color.tertiary_text_dark }, 82 { 0xff808080, android.R.color.tertiary_text_light }, 83 { 0x00000000, android.R.color.transparent }, 84 { 0xffffffff, android.R.color.white }, 85 { 0xff000000, android.R.color.widget_edittext_dark }, 86 }; 87 88 int[] systemColors = { 89 android.R.color.system_neutral1_0, 90 android.R.color.system_neutral1_10, 91 android.R.color.system_neutral1_50, 92 android.R.color.system_neutral1_100, 93 android.R.color.system_neutral1_200, 94 android.R.color.system_neutral1_300, 95 android.R.color.system_neutral1_400, 96 android.R.color.system_neutral1_500, 97 android.R.color.system_neutral1_600, 98 android.R.color.system_neutral1_700, 99 android.R.color.system_neutral1_800, 100 android.R.color.system_neutral1_900, 101 android.R.color.system_neutral1_1000, 102 android.R.color.system_neutral2_0, 103 android.R.color.system_neutral2_10, 104 android.R.color.system_neutral2_50, 105 android.R.color.system_neutral2_100, 106 android.R.color.system_neutral2_200, 107 android.R.color.system_neutral2_300, 108 android.R.color.system_neutral2_400, 109 android.R.color.system_neutral2_500, 110 android.R.color.system_neutral2_600, 111 android.R.color.system_neutral2_700, 112 android.R.color.system_neutral2_800, 113 android.R.color.system_neutral2_900, 114 android.R.color.system_neutral2_1000, 115 android.R.color.system_accent1_0, 116 android.R.color.system_accent1_10, 117 android.R.color.system_accent1_50, 118 android.R.color.system_accent1_100, 119 android.R.color.system_accent1_200, 120 android.R.color.system_accent1_300, 121 android.R.color.system_accent1_400, 122 android.R.color.system_accent1_500, 123 android.R.color.system_accent1_600, 124 android.R.color.system_accent1_700, 125 android.R.color.system_accent1_800, 126 android.R.color.system_accent1_900, 127 android.R.color.system_accent1_1000, 128 android.R.color.system_accent2_0, 129 android.R.color.system_accent2_10, 130 android.R.color.system_accent2_50, 131 android.R.color.system_accent2_100, 132 android.R.color.system_accent2_200, 133 android.R.color.system_accent2_300, 134 android.R.color.system_accent2_400, 135 android.R.color.system_accent2_500, 136 android.R.color.system_accent2_600, 137 android.R.color.system_accent2_700, 138 android.R.color.system_accent2_800, 139 android.R.color.system_accent2_900, 140 android.R.color.system_accent2_1000, 141 android.R.color.system_accent3_0, 142 android.R.color.system_accent3_10, 143 android.R.color.system_accent3_50, 144 android.R.color.system_accent3_100, 145 android.R.color.system_accent3_200, 146 android.R.color.system_accent3_300, 147 android.R.color.system_accent3_400, 148 android.R.color.system_accent3_500, 149 android.R.color.system_accent3_600, 150 android.R.color.system_accent3_700, 151 android.R.color.system_accent3_800, 152 android.R.color.system_accent3_900, 153 android.R.color.system_accent3_1000, 154 android.R.color.system_error_0, 155 android.R.color.system_error_10, 156 android.R.color.system_error_50, 157 android.R.color.system_error_100, 158 android.R.color.system_error_200, 159 android.R.color.system_error_300, 160 android.R.color.system_error_400, 161 android.R.color.system_error_500, 162 android.R.color.system_error_600, 163 android.R.color.system_error_700, 164 android.R.color.system_error_800, 165 android.R.color.system_error_900, 166 android.R.color.system_error_1000, 167 }; 168 169 int[] materialSystemColors = { 170 android.R.color.system_primary_container_light, 171 android.R.color.system_on_primary_container_light, 172 android.R.color.system_primary_light, 173 android.R.color.system_on_primary_light, 174 android.R.color.system_secondary_container_light, 175 android.R.color.system_on_secondary_container_light, 176 android.R.color.system_secondary_light, 177 android.R.color.system_on_secondary_light, 178 android.R.color.system_tertiary_container_light, 179 android.R.color.system_on_tertiary_container_light, 180 android.R.color.system_tertiary_light, 181 android.R.color.system_on_tertiary_light, 182 android.R.color.system_background_light, 183 android.R.color.system_on_background_light, 184 android.R.color.system_surface_light, 185 android.R.color.system_on_surface_light, 186 android.R.color.system_surface_container_low_light, 187 android.R.color.system_surface_container_lowest_light, 188 android.R.color.system_surface_container_light, 189 android.R.color.system_surface_container_high_light, 190 android.R.color.system_surface_container_highest_light, 191 android.R.color.system_surface_bright_light, 192 android.R.color.system_surface_dim_light, 193 android.R.color.system_surface_variant_light, 194 android.R.color.system_on_surface_variant_light, 195 android.R.color.system_outline_light, 196 android.R.color.system_outline_variant_light, 197 android.R.color.system_error_light, 198 android.R.color.system_on_error_light, 199 android.R.color.system_error_container_light, 200 android.R.color.system_on_error_container_light, 201 android.R.color.system_primary_fixed, 202 android.R.color.system_primary_fixed_dim, 203 android.R.color.system_on_primary_fixed, 204 android.R.color.system_on_primary_fixed_variant, 205 android.R.color.system_secondary_fixed, 206 android.R.color.system_secondary_fixed_dim, 207 android.R.color.system_on_secondary_fixed, 208 android.R.color.system_on_secondary_fixed_variant, 209 android.R.color.system_tertiary_fixed, 210 android.R.color.system_tertiary_fixed_dim, 211 android.R.color.system_on_tertiary_fixed, 212 android.R.color.system_on_tertiary_fixed_variant, 213 android.R.color.system_control_activated_light, 214 android.R.color.system_control_normal_light, 215 android.R.color.system_control_highlight_light, 216 android.R.color.system_text_primary_inverse_light, 217 android.R.color.system_text_secondary_and_tertiary_inverse_light, 218 android.R.color.system_text_primary_inverse_disable_only_light, 219 android.R.color.system_text_secondary_and_tertiary_inverse_disabled_light, 220 android.R.color.system_text_hint_inverse_light, 221 android.R.color.system_palette_key_color_primary_light, 222 android.R.color.system_palette_key_color_secondary_light, 223 android.R.color.system_palette_key_color_tertiary_light, 224 android.R.color.system_palette_key_color_neutral_light, 225 android.R.color.system_palette_key_color_neutral_variant_light, 226 android.R.color.system_primary_container_dark, 227 android.R.color.system_on_primary_container_dark, 228 android.R.color.system_primary_dark, 229 android.R.color.system_on_primary_dark, 230 android.R.color.system_secondary_container_dark, 231 android.R.color.system_on_secondary_container_dark, 232 android.R.color.system_secondary_dark, 233 android.R.color.system_on_secondary_dark, 234 android.R.color.system_tertiary_container_dark, 235 android.R.color.system_on_tertiary_container_dark, 236 android.R.color.system_tertiary_dark, 237 android.R.color.system_on_tertiary_dark, 238 android.R.color.system_background_dark, 239 android.R.color.system_on_background_dark, 240 android.R.color.system_surface_dark, 241 android.R.color.system_on_surface_dark, 242 android.R.color.system_surface_container_low_dark, 243 android.R.color.system_surface_container_lowest_dark, 244 android.R.color.system_surface_container_dark, 245 android.R.color.system_surface_container_high_dark, 246 android.R.color.system_surface_container_highest_dark, 247 android.R.color.system_surface_bright_dark, 248 android.R.color.system_surface_dim_dark, 249 android.R.color.system_surface_variant_dark, 250 android.R.color.system_on_surface_variant_dark, 251 android.R.color.system_outline_dark, 252 android.R.color.system_outline_variant_dark, 253 android.R.color.system_error_dark, 254 android.R.color.system_on_error_dark, 255 android.R.color.system_error_container_dark, 256 android.R.color.system_on_error_container_dark, 257 android.R.color.system_control_activated_dark, 258 android.R.color.system_control_normal_dark, 259 android.R.color.system_control_highlight_dark, 260 android.R.color.system_text_primary_inverse_dark, 261 android.R.color.system_text_secondary_and_tertiary_inverse_dark, 262 android.R.color.system_text_primary_inverse_disable_only_dark, 263 android.R.color.system_text_secondary_and_tertiary_inverse_disabled_dark, 264 android.R.color.system_text_hint_inverse_dark, 265 android.R.color.system_palette_key_color_primary_dark, 266 android.R.color.system_palette_key_color_secondary_dark, 267 android.R.color.system_palette_key_color_tertiary_dark, 268 android.R.color.system_palette_key_color_neutral_dark, 269 android.R.color.system_palette_key_color_neutral_variant_dark, 270 android.R.color.system_surface_disabled, 271 android.R.color.system_on_surface_disabled, 272 android.R.color.system_outline_disabled, 273 }; 274 275 List<Integer> expectedColorStateLists = Arrays.asList( 276 android.R.color.primary_text_dark, 277 android.R.color.primary_text_dark_nodisable, 278 android.R.color.primary_text_light, 279 android.R.color.primary_text_light_nodisable, 280 android.R.color.secondary_text_dark, 281 android.R.color.secondary_text_dark_nodisable, 282 android.R.color.secondary_text_light, 283 android.R.color.secondary_text_light_nodisable, 284 android.R.color.tab_indicator_text, 285 android.R.color.tertiary_text_dark, 286 android.R.color.tertiary_text_light, 287 android.R.color.widget_edittext_dark 288 ); 289 290 Resources resources = getInstrumentation().getTargetContext().getResources(); 291 for (int[] pair : colors) { 292 final int resourceId = pair[1]; 293 final int expectedColor = pair[0]; 294 295 // validate color from getColor 296 int observedColor = resources.getColor(resourceId, null); 297 assertEquals("Color = " + Integer.toHexString(observedColor) + ", " 298 + Integer.toHexString(expectedColor) + " expected", 299 expectedColor, 300 observedColor); 301 302 // validate color from getValue 303 TypedValue value = new TypedValue(); 304 resources.getValue(resourceId, value, true); 305 306 // colors shouldn't depend on config changes 307 assertEquals(0, value.changingConfigurations); 308 309 if (expectedColorStateLists.contains(resourceId)) { 310 // ColorStateLists are strings 311 assertEquals("CSLs should be strings", TypedValue.TYPE_STRING, value.type); 312 } else { 313 // colors should be raw ints 314 assertTrue("Type should be int", 315 value.type >= TypedValue.TYPE_FIRST_INT 316 && value.type <= TypedValue.TYPE_LAST_INT); 317 318 // Validate color from getValue 319 assertEquals("Color should be expected value", expectedColor, value.data); 320 } 321 } 322 323 // System-API colors are used to allow updateable platform components to use the same colors 324 // as the system. The actual value of the color does not matter. Hence only enforce that 325 // 'colors' contains all the public colors and ignore System-api colors. 326 ArrayList<String> missingColors = new ArrayList<>(); 327 ArrayList<Integer> requiredPublicApiColorResIds = new ArrayList<>(); 328 requiredPublicApiColorResIds.addAll(Arrays.stream(colors).map(pair -> pair[1]).toList()); 329 requiredPublicApiColorResIds.addAll(Arrays.stream(systemColors).boxed().toList()); 330 requiredPublicApiColorResIds.addAll(Arrays.stream(materialSystemColors).boxed().toList()); 331 332 Set<Integer> availablePublicApiColorResIds = new ArraySet<>(); 333 for (Field declaredColor : android.R.color.class.getDeclaredFields()) { 334 if (Arrays.stream(declaredColor.getDeclaredAnnotations()).anyMatch( 335 (Annotation a) -> a.toString().contains("SystemApi"))) { 336 Log.i(LOG_TAG, declaredColor.getName() + " is SystemApi"); 337 continue; 338 } 339 Integer colorValue = -1; 340 try { 341 colorValue = (Integer) declaredColor.get(null); 342 } catch (IllegalAccessException ignored) { } 343 if (colorValue != -1) { 344 availablePublicApiColorResIds.add(colorValue); 345 } 346 } 347 348 for (Integer requiredColorResId : requiredPublicApiColorResIds) { 349 if (!availablePublicApiColorResIds.contains(requiredColorResId)) { 350 missingColors.add(resources.getResourceName(requiredColorResId)); 351 } 352 } 353 354 assertTrue( 355 "android.R.color misses required color resources. Declared in list,but not " 356 + "installed : " 357 + missingColors, missingColors.isEmpty()); 358 } 359 @Test testAlpha()360 public void testAlpha() { 361 assertEquals(0xff, Color.alpha(Color.RED)); 362 assertEquals(0xff, Color.alpha(Color.YELLOW)); 363 } 364 365 @Test testArgb()366 public void testArgb() { 367 assertEquals(Color.RED, Color.argb(0xff, 0xff, 0x00, 0x00)); 368 assertEquals(Color.YELLOW, Color.argb(0xff, 0xff, 0xff, 0x00)); 369 assertEquals(Color.RED, Color.argb(1.0f, 1.0f, 0.0f, 0.0f)); 370 assertEquals(Color.YELLOW, Color.argb(1.0f, 1.0f, 1.0f, 0.0f)); 371 } 372 373 @Test testBlue()374 public void testBlue() { 375 assertEquals(0x00, Color.blue(Color.RED)); 376 assertEquals(0x00, Color.blue(Color.YELLOW)); 377 } 378 379 @Test testGreen()380 public void testGreen() { 381 assertEquals(0x00, Color.green(Color.RED)); 382 assertEquals(0xff, Color.green(Color.GREEN)); 383 } 384 385 @Test(expected = RuntimeException.class) testHSVToColorArrayTooShort()386 public void testHSVToColorArrayTooShort() { 387 // abnormal case: hsv length less than 3 388 float[] hsv = new float[2]; 389 Color.HSVToColor(hsv); 390 } 391 392 @Test testHSVToColor()393 public void testHSVToColor() { 394 float[] hsv = new float[3]; 395 Color.colorToHSV(Color.RED, hsv); 396 assertEquals(Color.RED, Color.HSVToColor(hsv)); 397 } 398 399 @Test testHSVToColorWithAlpha()400 public void testHSVToColorWithAlpha() { 401 float[] hsv = new float[3]; 402 Color.colorToHSV(Color.RED, hsv); 403 assertEquals(Color.RED, Color.HSVToColor(0xff, hsv)); 404 } 405 406 @Test(expected = IllegalArgumentException.class) testParseColorStringOfInvalidLength()407 public void testParseColorStringOfInvalidLength() { 408 // abnormal case: colorString starts with '#' but length is neither 7 nor 9 409 Color.parseColor("#ff00ff0"); 410 } 411 412 @Test testParseColor()413 public void testParseColor() { 414 assertEquals(Color.RED, Color.parseColor("#ff0000")); 415 assertEquals(Color.RED, Color.parseColor("#ffff0000")); 416 417 assertEquals(Color.BLACK, Color.parseColor("black")); 418 assertEquals(Color.DKGRAY, Color.parseColor("darkgray")); 419 assertEquals(Color.GRAY, Color.parseColor("gray")); 420 assertEquals(Color.LTGRAY, Color.parseColor("lightgray")); 421 assertEquals(Color.WHITE, Color.parseColor("white")); 422 assertEquals(Color.RED, Color.parseColor("red")); 423 assertEquals(Color.GREEN, Color.parseColor("green")); 424 assertEquals(Color.BLUE, Color.parseColor("blue")); 425 assertEquals(Color.YELLOW, Color.parseColor("yellow")); 426 assertEquals(Color.CYAN, Color.parseColor("cyan")); 427 assertEquals(Color.MAGENTA, Color.parseColor("magenta")); 428 } 429 430 @Test(expected = IllegalArgumentException.class) testParseColorUnsupportedFormat()431 public void testParseColorUnsupportedFormat() { 432 // abnormal case: colorString doesn't start with '#' and is unknown color 433 Color.parseColor("hello"); 434 } 435 436 @Test testRed()437 public void testRed() { 438 assertEquals(0xff, Color.red(Color.RED)); 439 assertEquals(0xff, Color.red(Color.YELLOW)); 440 } 441 442 @Test testRgb()443 public void testRgb() { 444 assertEquals(Color.RED, Color.rgb(0xff, 0x00, 0x00)); 445 assertEquals(Color.YELLOW, Color.rgb(0xff, 0xff, 0x00)); 446 assertEquals(Color.RED, Color.rgb(1.0f, 0.0f, 0.0f)); 447 assertEquals(Color.YELLOW, Color.rgb(1.0f, 1.0f, 0.0f)); 448 } 449 450 @Test(expected = RuntimeException.class) testRGBToHSVArrayTooShort()451 public void testRGBToHSVArrayTooShort() { 452 // abnormal case: hsv length less than 3 453 float[] hsv = new float[2]; 454 Color.RGBToHSV(0xff, 0x00, 0x00, hsv); 455 } 456 457 @Test testRGBToHSV()458 public void testRGBToHSV() { 459 float[] hsv = new float[3]; 460 Color.RGBToHSV(0xff, 0x00, 0x00, hsv); 461 assertEquals(Color.RED, Color.HSVToColor(hsv)); 462 } 463 464 @Test testLuminance()465 public void testLuminance() { 466 assertEquals(0, Color.luminance(Color.BLACK), 0); 467 float eps = 0.000001f; 468 assertEquals(0.0722, Color.luminance(Color.BLUE), eps); 469 assertEquals(0.2126, Color.luminance(Color.RED), eps); 470 assertEquals(0.7152, Color.luminance(Color.GREEN), eps); 471 assertEquals(1, Color.luminance(Color.WHITE), 0); 472 } 473 } 474