1 /* 2 * Copyright (C) 2018 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 com.android.overlaytest; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 25 import android.content.Context; 26 import android.content.om.OverlayIdentifier; 27 import android.content.res.AssetManager; 28 import android.content.res.Configuration; 29 import android.content.res.Resources; 30 import android.content.res.XmlResourceParser; 31 import android.os.LocaleList; 32 import android.util.AttributeSet; 33 import android.util.TypedValue; 34 import android.util.Xml; 35 import android.view.LayoutInflater; 36 import android.view.View; 37 38 import androidx.test.InstrumentationRegistry; 39 40 import com.android.compatibility.common.util.AmUtils; 41 import com.android.internal.util.ArrayUtils; 42 import com.android.overlaytest.view.TestTextView; 43 44 import org.junit.Before; 45 import org.junit.BeforeClass; 46 import org.junit.Ignore; 47 import org.junit.Test; 48 49 import java.io.BufferedReader; 50 import java.io.InputStream; 51 import java.io.InputStreamReader; 52 import java.nio.charset.StandardCharsets; 53 import java.util.Locale; 54 55 @Ignore 56 public abstract class OverlayBaseTest { 57 private Context mContext; 58 private Resources mResources; 59 private final int mMode; 60 static final int MODE_NO_OVERLAY = 0; 61 static final int MODE_SINGLE_OVERLAY = 1; 62 static final int MODE_MULTIPLE_OVERLAYS = 2; 63 64 static final OverlayIdentifier APP_OVERLAY_ONE_PKG = 65 new OverlayIdentifier("com.android.overlaytest.app_overlay_one"); 66 static final OverlayIdentifier APP_OVERLAY_TWO_PKG = 67 new OverlayIdentifier("com.android.overlaytest.app_overlay_two"); 68 static final OverlayIdentifier FRAMEWORK_OVERLAY_PKG = 69 new OverlayIdentifier("com.android.overlaytest.framework"); 70 OverlayBaseTest(int mode)71 protected OverlayBaseTest(int mode) { 72 mMode = mode; 73 } 74 75 @BeforeClass setUpClass()76 public static void setUpClass() { 77 // Wait for package_added broadcasts to be handled so that OverlayManagerService 78 // can update it's internal state with the new packages. 79 AmUtils.waitForBroadcastBarrier(); 80 } 81 82 @Before setUp()83 public void setUp() { 84 mContext = InstrumentationRegistry.getContext(); 85 mResources = mContext.getResources(); 86 } 87 calculateRawResourceChecksum(int resId)88 private int calculateRawResourceChecksum(int resId) throws Throwable { 89 try (InputStream input = mResources.openRawResource(resId)) { 90 int ch, checksum = 0; 91 while ((ch = input.read()) != -1) { 92 checksum = (checksum + ch) % 0xffddbb00; 93 } 94 return checksum; 95 } 96 } 97 setLocale(Locale locale)98 private void setLocale(Locale locale) { 99 final LocaleList locales = new LocaleList(locale); 100 LocaleList.setDefault(locales); 101 Configuration config = new Configuration(); 102 config.setLocales(locales); 103 mResources.updateConfiguration(config, mResources.getDisplayMetrics()); 104 } 105 getExpected(boolean no, boolean so, boolean mo)106 private boolean getExpected(boolean no, boolean so, boolean mo) { 107 switch (mMode) { 108 case MODE_NO_OVERLAY: 109 return no; 110 case MODE_SINGLE_OVERLAY: 111 return so; 112 case MODE_MULTIPLE_OVERLAYS: 113 return mo; 114 default: 115 fail("Unknown mode!"); 116 return no; 117 } 118 } 119 getExpected(String no, String so, String mo)120 private String getExpected(String no, String so, String mo) { 121 switch (mMode) { 122 case MODE_NO_OVERLAY: 123 return no; 124 case MODE_SINGLE_OVERLAY: 125 return so; 126 case MODE_MULTIPLE_OVERLAYS: 127 return mo; 128 default: 129 fail("Unknown mode!"); 130 return no; 131 } 132 } 133 getExpected(int no, int so, int mo)134 private int getExpected(int no, int so, int mo) { 135 switch (mMode) { 136 case MODE_NO_OVERLAY: 137 return no; 138 case MODE_SINGLE_OVERLAY: 139 return so; 140 case MODE_MULTIPLE_OVERLAYS: 141 return mo; 142 default: 143 fail("Unknown mode!"); 144 return no; 145 } 146 } 147 getExpected(int[] no, int[] so, int[] mo)148 private int[] getExpected(int[] no, int[] so, int[] mo) { 149 switch (mMode) { 150 case MODE_NO_OVERLAY: 151 return no; 152 case MODE_SINGLE_OVERLAY: 153 return so; 154 case MODE_MULTIPLE_OVERLAYS: 155 return mo; 156 default: 157 fail("Unknown mode!"); 158 return no; 159 } 160 } 161 assertResource(int resId, boolean no, boolean so, boolean mo)162 private void assertResource(int resId, boolean no, boolean so, boolean mo) throws Throwable { 163 boolean expected = getExpected(no, so, mo); 164 boolean actual = mResources.getBoolean(resId); 165 assertEquals(expected, actual); 166 } 167 assertResource(int resId, int no, int so, int mo)168 private void assertResource(int resId, int no, int so, int mo) throws Throwable { 169 int expected = getExpected(no, so, mo); 170 int actual = mResources.getInteger(resId); 171 assertEquals(expected, actual); 172 } 173 assertResource(int resId, String no, String so, String mo)174 private void assertResource(int resId, String no, String so, String mo) throws Throwable { 175 String expected = getExpected(no, so, mo); 176 String actual = mResources.getString(resId); 177 assertEquals(expected, actual); 178 } 179 assertResource(int resId, int[] no, int[] so, int[] mo)180 private void assertResource(int resId, int[] no, int[] so, int[] mo) throws Throwable { 181 int[] expected = getExpected(no, so, mo); 182 int[] actual = mResources.getIntArray(resId); 183 assertEquals("length:", expected.length, actual.length); 184 for (int i = 0; i < actual.length; ++i) { 185 assertEquals("index " + i + ":", actual[i], expected[i]); 186 } 187 } 188 189 @Test testFrameworkBooleanOverlay()190 public void testFrameworkBooleanOverlay() throws Throwable { 191 // config_annoy_dianne has the value: 192 // - true when no overlay exists (MODE_NO_OVERLAY) 193 // - false when a single overlay exists (MODE_SINGLE_OVERLAY) 194 // - false when multiple overlays exists (MODE_MULTIPLE_OVERLAYS) 195 final int resId = com.android.internal.R.bool.config_annoy_dianne; 196 assertResource(resId, true, false, false); 197 } 198 199 @Test testBooleanOverlay()200 public void testBooleanOverlay() throws Throwable { 201 // usually_false has the value: 202 // - false when no overlay exists (MODE_NO_OVERLAY) 203 // - true when a single overlay exists (MODE_SINGLE_OVERLAY) 204 // - false when multiple overlays exists (MODE_MULTIPLE_OVERLAYS) 205 final int resId = R.bool.usually_false; 206 assertResource(resId, false, true, false); 207 } 208 209 @Test testBoolean()210 public void testBoolean() throws Throwable { 211 // always_true has no overlay 212 final int resId = R.bool.always_true; 213 assertResource(resId, true, true, true); 214 } 215 216 @Test testIntegerArrayOverlay()217 public void testIntegerArrayOverlay() throws Throwable { 218 // fibonacci has values: 219 // - eight first values of Fibonacci sequence, when no overlay exists (MODE_NO_OVERLAY) 220 // - eight first values of Fibonacci sequence (reversed), for single and multiple overlays 221 // (MODE_SINGLE_OVERLAY, MODE_MULTIPLE_OVERLAYS) 222 final int resId = R.array.fibonacci; 223 assertResource(resId, 224 new int[]{1, 1, 2, 3, 5, 8, 13, 21}, 225 new int[]{21, 13, 8, 5, 3, 2, 1, 1}, 226 new int[]{21, 13, 8, 5, 3, 2, 1, 1}); 227 } 228 229 @Test testIntegerArray()230 public void testIntegerArray() throws Throwable { 231 // prime_numbers has no overlay 232 final int resId = R.array.prime_numbers; 233 final int[] expected = {2, 3, 5, 7, 11, 13, 17, 19}; 234 assertResource(resId, expected, expected, expected); 235 } 236 237 @Test testDrawable()238 public void testDrawable() throws Throwable { 239 // drawable-nodpi/drawable has overlay (default config) 240 final int resId = R.drawable.drawable; 241 int actual = calculateRawResourceChecksum(resId); 242 int expected = 0; 243 switch (mMode) { 244 case MODE_NO_OVERLAY: 245 expected = 0x00005665; 246 break; 247 case MODE_SINGLE_OVERLAY: 248 case MODE_MULTIPLE_OVERLAYS: 249 expected = 0x000051da; 250 break; 251 default: 252 fail("Unknown mode " + mMode); 253 } 254 assertEquals(expected, actual); 255 } 256 257 @Test testAppString()258 public void testAppString() throws Throwable { 259 final int resId = R.string.str; 260 assertResource(resId, "none", "single", "multiple"); 261 } 262 263 @Test testApp2()264 public void testApp2() throws Throwable { 265 final int resId = R.string.str2; // only in base package and first app overlay 266 assertResource(resId, "none", "single", "single"); 267 } 268 269 @Test testAppXml()270 public void testAppXml() throws Throwable { 271 int expected = getExpected(0, 1, 2); 272 int actual = -1; 273 XmlResourceParser parser = mResources.getXml(R.xml.integer); 274 int type = parser.getEventType(); 275 while (type != XmlResourceParser.END_DOCUMENT && actual == -1) { 276 if (type == XmlResourceParser.START_TAG && "integer".equals(parser.getName())) { 277 AttributeSet as = Xml.asAttributeSet(parser); 278 actual = as.getAttributeIntValue(null, "value", -1); 279 } 280 type = parser.next(); 281 } 282 parser.close(); 283 assertEquals(expected, actual); 284 } 285 286 @Test testAppRaw()287 public void testAppRaw() throws Throwable { 288 final int resId = R.raw.lorem_ipsum; 289 290 InputStream input = null; 291 BufferedReader reader = null; 292 String actual = ""; 293 try { 294 input = mResources.openRawResource(resId); 295 reader = new BufferedReader(new InputStreamReader(input)); 296 actual = reader.readLine(); 297 } finally { 298 if (reader != null) { 299 reader.close(); 300 } 301 if (input != null) { 302 input.close(); 303 } 304 } 305 306 final String no = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " 307 + "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim " 308 + "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo " 309 + "consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse " 310 + "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " 311 + "proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; 312 final String so = "Lorem ipsum: single overlay."; 313 final String mo = "Lorem ipsum: multiple overlays."; 314 315 assertEquals(getExpected(no, so, mo), actual); 316 } 317 318 @Test testAssetsNotPossibleToOverlay()319 public void testAssetsNotPossibleToOverlay() throws Throwable { 320 final AssetManager am = mResources.getAssets(); 321 322 // AssetManager#list will include assets from all loaded non-overlay 323 // APKs, including the framework; framework-res.apk contains at least 324 // assets/{images,webkit}. Rather than checking the list, verify that 325 // assets only present in overlays are never part of the list. 326 String[] files = am.list(""); 327 assertTrue(ArrayUtils.contains(files, "package-name.txt")); 328 assertFalse(ArrayUtils.contains(files, "foo.txt")); 329 assertFalse(ArrayUtils.contains(files, "bar.txt")); 330 331 String contents = null; 332 try (InputStream is = am.open("package-name.txt")) { 333 final BufferedReader reader = new BufferedReader( 334 new InputStreamReader(is, StandardCharsets.UTF_8)); 335 StringBuilder str = new StringBuilder(); 336 String line; 337 while ((line = reader.readLine()) != null) { 338 str.append(line); 339 } 340 contents = str.toString(); 341 } 342 assertEquals("com.android.overlaytest", contents); 343 } 344 345 @Test testRewrite()346 public void testRewrite() throws Throwable { 347 final TypedValue result = new TypedValue(); 348 mResources.getValue(R.string.str, result, true); 349 assertEquals(result.resourceId & 0xff000000, 0x7f000000); 350 } 351 352 @Test testOverlayLayout()353 public void testOverlayLayout() throws Throwable { 354 final LayoutInflater inflater = LayoutInflater.from(mContext); 355 final View layout = inflater.inflate(R.layout.layout, null); 356 assertNotNull(layout.findViewById(R.id.view_1)); 357 358 final TestTextView view2 = layout.findViewById(R.id.view_2); 359 assertNotNull(view2); 360 switch (mMode) { 361 case MODE_NO_OVERLAY: 362 assertEquals("none", view2.getCustomAttributeValue()); 363 break; 364 case MODE_SINGLE_OVERLAY: 365 assertEquals("single", view2.getCustomAttributeValue()); 366 break; 367 case MODE_MULTIPLE_OVERLAYS: 368 assertEquals("multiple", view2.getCustomAttributeValue()); 369 break; 370 default: 371 fail("Unknown mode " + mMode); 372 } 373 374 final TestTextView view3 = layout.findViewById(R.id.view_3); 375 assertNotNull(view3); 376 switch (mMode) { 377 case MODE_NO_OVERLAY: 378 assertEquals("none", view3.getCustomAttributeValue()); 379 break; 380 case MODE_SINGLE_OVERLAY: 381 case MODE_MULTIPLE_OVERLAYS: 382 assertEquals("overlaid", view3.getCustomAttributeValue()); 383 break; 384 default: 385 fail("Unknown mode " + mMode); 386 } 387 } 388 389 /* 390 * testMatrix* tests 391 * 392 * The naming convention textMatrixABCDEF refers to in which packages and 393 * which configurations a resource is defined (1 if the resource is 394 * defined). If defined, a slot is always given the same value. 395 * 396 * SLOT PACKAGE CONFIGURATION VALUE 397 * A target package (default) 100 398 * B target package -sv 200 399 * C AppOverlayOne (default) 300 400 * D AppOverlayOne -sv 400 401 * E AppOverlayTwo (default) 500 402 * F AppOverlayTwo -sv 600 403 * 404 * Example: in testMatrix101110, the base package defines the 405 * R.integer.matrix101110 resource for the default configuration (value 406 * 100), OverlayAppFirst defines it for both default and Swedish 407 * configurations (values 300 and 400, respectively), and OverlayAppSecond 408 * defines it for the default configuration (value 500). If both overlays 409 * are loaded, the expected value after setting the language to Swedish is 410 * 400. 411 */ 412 @Test testMatrix100000()413 public void testMatrix100000() throws Throwable { 414 final int resId = R.integer.matrix_100000; 415 setLocale(new Locale("sv", "SE")); 416 assertResource(resId, 100, 100, 100); 417 } 418 419 @Test testMatrix100001()420 public void testMatrix100001() throws Throwable { 421 final int resId = R.integer.matrix_100001; 422 setLocale(new Locale("sv", "SE")); 423 assertResource(resId, 100, 100, 600); 424 } 425 426 @Test testMatrix100010()427 public void testMatrix100010() throws Throwable { 428 final int resId = R.integer.matrix_100010; 429 setLocale(new Locale("sv", "SE")); 430 assertResource(resId, 100, 100, 500); 431 } 432 433 @Test testMatrix100011()434 public void testMatrix100011() throws Throwable { 435 final int resId = R.integer.matrix_100011; 436 setLocale(new Locale("sv", "SE")); 437 assertResource(resId, 100, 100, 600); 438 } 439 440 @Test testMatrix100100()441 public void testMatrix100100() throws Throwable { 442 final int resId = R.integer.matrix_100100; 443 setLocale(new Locale("sv", "SE")); 444 assertResource(resId, 100, 400, 400); 445 } 446 447 @Test testMatrix100101()448 public void testMatrix100101() throws Throwable { 449 final int resId = R.integer.matrix_100101; 450 setLocale(new Locale("sv", "SE")); 451 assertResource(resId, 100, 400, 600); 452 } 453 454 @Test testMatrix100110()455 public void testMatrix100110() throws Throwable { 456 final int resId = R.integer.matrix_100110; 457 setLocale(new Locale("sv", "SE")); 458 assertResource(resId, 100, 400, 400); 459 } 460 461 @Test testMatrix100111()462 public void testMatrix100111() throws Throwable { 463 final int resId = R.integer.matrix_100111; 464 setLocale(new Locale("sv", "SE")); 465 assertResource(resId, 100, 400, 600); 466 } 467 468 @Test testMatrix101000()469 public void testMatrix101000() throws Throwable { 470 final int resId = R.integer.matrix_101000; 471 setLocale(new Locale("sv", "SE")); 472 assertResource(resId, 100, 300, 300); 473 } 474 475 @Test testMatrix101001()476 public void testMatrix101001() throws Throwable { 477 final int resId = R.integer.matrix_101001; 478 setLocale(new Locale("sv", "SE")); 479 assertResource(resId, 100, 300, 600); 480 } 481 482 @Test testMatrix101010()483 public void testMatrix101010() throws Throwable { 484 final int resId = R.integer.matrix_101010; 485 setLocale(new Locale("sv", "SE")); 486 assertResource(resId, 100, 300, 500); 487 } 488 489 @Test testMatrix101011()490 public void testMatrix101011() throws Throwable { 491 final int resId = R.integer.matrix_101011; 492 setLocale(new Locale("sv", "SE")); 493 assertResource(resId, 100, 300, 600); 494 } 495 496 @Test testMatrix101100()497 public void testMatrix101100() throws Throwable { 498 final int resId = R.integer.matrix_101100; 499 setLocale(new Locale("sv", "SE")); 500 assertResource(resId, 100, 400, 400); 501 } 502 503 @Test testMatrix101101()504 public void testMatrix101101() throws Throwable { 505 final int resId = R.integer.matrix_101101; 506 setLocale(new Locale("sv", "SE")); 507 assertResource(resId, 100, 400, 600); 508 } 509 510 @Test testMatrix101110()511 public void testMatrix101110() throws Throwable { 512 final int resId = R.integer.matrix_101110; 513 setLocale(new Locale("sv", "SE")); 514 assertResource(resId, 100, 400, 400); 515 } 516 517 @Test testMatrix101111()518 public void testMatrix101111() throws Throwable { 519 final int resId = R.integer.matrix_101111; 520 setLocale(new Locale("sv", "SE")); 521 assertResource(resId, 100, 400, 600); 522 } 523 524 @Test testMatrix110000()525 public void testMatrix110000() throws Throwable { 526 final int resId = R.integer.matrix_110000; 527 setLocale(new Locale("sv", "SE")); 528 assertResource(resId, 200, 200, 200); 529 } 530 531 @Test testMatrix110001()532 public void testMatrix110001() throws Throwable { 533 final int resId = R.integer.matrix_110001; 534 setLocale(new Locale("sv", "SE")); 535 assertResource(resId, 200, 200, 600); 536 } 537 538 @Test testMatrix110010()539 public void testMatrix110010() throws Throwable { 540 final int resId = R.integer.matrix_110010; 541 setLocale(new Locale("sv", "SE")); 542 assertResource(resId, 200, 200, 200); 543 } 544 545 @Test testMatrix110011()546 public void testMatrix110011() throws Throwable { 547 final int resId = R.integer.matrix_110011; 548 setLocale(new Locale("sv", "SE")); 549 assertResource(resId, 200, 200, 600); 550 } 551 552 @Test testMatrix110100()553 public void testMatrix110100() throws Throwable { 554 final int resId = R.integer.matrix_110100; 555 setLocale(new Locale("sv", "SE")); 556 assertResource(resId, 200, 400, 400); 557 } 558 559 @Test testMatrix110101()560 public void testMatrix110101() throws Throwable { 561 final int resId = R.integer.matrix_110101; 562 setLocale(new Locale("sv", "SE")); 563 assertResource(resId, 200, 400, 600); 564 } 565 566 @Test testMatrix110110()567 public void testMatrix110110() throws Throwable { 568 final int resId = R.integer.matrix_110110; 569 setLocale(new Locale("sv", "SE")); 570 assertResource(resId, 200, 400, 400); 571 } 572 573 @Test testMatrix110111()574 public void testMatrix110111() throws Throwable { 575 final int resId = R.integer.matrix_110111; 576 setLocale(new Locale("sv", "SE")); 577 assertResource(resId, 200, 400, 600); 578 } 579 580 @Test testMatrix111000()581 public void testMatrix111000() throws Throwable { 582 final int resId = R.integer.matrix_111000; 583 setLocale(new Locale("sv", "SE")); 584 assertResource(resId, 200, 200, 200); 585 } 586 587 @Test testMatrix111001()588 public void testMatrix111001() throws Throwable { 589 final int resId = R.integer.matrix_111001; 590 setLocale(new Locale("sv", "SE")); 591 assertResource(resId, 200, 200, 600); 592 } 593 594 @Test testMatrix111010()595 public void testMatrix111010() throws Throwable { 596 final int resId = R.integer.matrix_111010; 597 setLocale(new Locale("sv", "SE")); 598 assertResource(resId, 200, 200, 200); 599 } 600 601 @Test testMatrix111011()602 public void testMatrix111011() throws Throwable { 603 final int resId = R.integer.matrix_111011; 604 setLocale(new Locale("sv", "SE")); 605 assertResource(resId, 200, 200, 600); 606 } 607 608 @Test testMatrix111100()609 public void testMatrix111100() throws Throwable { 610 final int resId = R.integer.matrix_111100; 611 setLocale(new Locale("sv", "SE")); 612 assertResource(resId, 200, 400, 400); 613 } 614 615 @Test testMatrix111101()616 public void testMatrix111101() throws Throwable { 617 final int resId = R.integer.matrix_111101; 618 setLocale(new Locale("sv", "SE")); 619 assertResource(resId, 200, 400, 600); 620 } 621 622 @Test testMatrix111110()623 public void testMatrix111110() throws Throwable { 624 final int resId = R.integer.matrix_111110; 625 setLocale(new Locale("sv", "SE")); 626 assertResource(resId, 200, 400, 400); 627 } 628 629 @Test testMatrix111111()630 public void testMatrix111111() throws Throwable { 631 final int resId = R.integer.matrix_111111; 632 setLocale(new Locale("sv", "SE")); 633 assertResource(resId, 200, 400, 600); 634 } 635 } 636