1 /* 2 * Copyright (C) 2009 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 android.content.res.cts; 18 19 import java.util.Locale; 20 21 import android.content.res.AssetManager; 22 import android.content.res.Configuration; 23 import android.content.res.Resources; 24 import android.content.res.TypedArray; 25 import android.content.res.Resources.NotFoundException; 26 import android.test.AndroidTestCase; 27 import android.test.suitebuilder.annotation.MediumTest; 28 import android.test.suitebuilder.annotation.SmallTest; 29 import android.util.DisplayMetrics; 30 31 import com.android.cts.stub.R; 32 33 public class ConfigTest extends AndroidTestCase { 34 enum Properties { 35 LANGUAGE, 36 COUNTRY, 37 MCC, 38 MNC, 39 TOUCHSCREEN, 40 KEYBOARD, 41 KEYBOARDHIDDEN, 42 NAVIGATION, 43 ORIENTATION, 44 WIDTH, 45 HEIGHT, 46 DENSITY 47 } 48 49 private static void checkValue(final Resources res, final int resId, 50 final String expectedValue) { 51 try { 52 final String actual = res.getString(resId); 53 assertNotNull("Returned wrong configuration-based simple value: expected <nothing>, " 54 + "got '" + actual + "' from resource 0x" + Integer.toHexString(resId), 55 expectedValue); 56 assertEquals("Returned wrong configuration-based simple value: expected '" 57 + expectedValue + "', got '" + actual + "' from resource 0x" 58 + Integer.toHexString(resId), expectedValue, actual); 59 } catch (NotFoundException e) { 60 assertNull("Resource not found for configuration-based simple value: expecting \"" 61 + expectedValue + "\"", expectedValue); 62 } 63 } 64 65 private static void checkValue(final Resources res, final int resId, 66 final int[] styleable, final String[] expectedValues) { 67 final Resources.Theme theme = res.newTheme(); 68 final TypedArray sa = theme.obtainStyledAttributes(resId, styleable); 69 for (int i = 0; i < styleable.length; i++) { 70 final String actual = sa.getString(i); 71 assertEquals("Returned wrong configuration-based style value: expected '" 72 + expectedValues[i] + "', got '" + actual + "' from attr " 73 + i + " of resource 0x" + Integer.toHexString(resId), 74 actual, expectedValues[i]); 75 } 76 sa.recycle(); 77 } 78 79 private class TotalConfig { 80 private Configuration mConfig; 81 private DisplayMetrics mMetrics; 82 83 public TotalConfig() { 84 mConfig = new Configuration(); 85 // don't rely on build settings - they may change 86 mConfig.locale = new Locale("en", "US"); 87 mConfig.mcc = 310; 88 mConfig.mnc = 001; // unused 89 mConfig.touchscreen = Configuration.TOUCHSCREEN_FINGER; 90 mConfig.keyboard = Configuration.KEYBOARD_QWERTY; 91 mConfig.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES; 92 mConfig.navigation = Configuration.NAVIGATION_TRACKBALL; 93 mConfig.orientation = Configuration.ORIENTATION_PORTRAIT; 94 95 mMetrics = new DisplayMetrics(); 96 mMetrics.widthPixels = 200; 97 mMetrics.heightPixels = 320; 98 mMetrics.density = 1; 99 } 100 101 public void setProperty(final Properties p, final int value) { 102 switch(p) { 103 case MCC: 104 mConfig.mcc = value; 105 break; 106 case MNC: 107 mConfig.mnc = value; 108 break; 109 case TOUCHSCREEN: 110 mConfig.touchscreen = value; 111 break; 112 case KEYBOARD: 113 mConfig.keyboard = value; 114 break; 115 case KEYBOARDHIDDEN: 116 mConfig.keyboardHidden = value; 117 break; 118 case NAVIGATION: 119 mConfig.navigation = value; 120 break; 121 case ORIENTATION: 122 mConfig.orientation = value; 123 break; 124 case WIDTH: 125 mMetrics.widthPixels = value; 126 break; 127 case HEIGHT: 128 mMetrics.heightPixels = value; 129 break; 130 case DENSITY: 131 // this is the ratio from the standard 132 133 mMetrics.density = (((float)value)/((float)DisplayMetrics.DENSITY_DEFAULT)); 134 break; 135 default: 136 assert(false); 137 break; 138 } 139 } 140 141 public void setProperty(final Properties p, final String value) { 142 switch(p) { 143 case LANGUAGE: 144 final String oldCountry = mConfig.locale.getCountry(); 145 mConfig.locale = new Locale(value, oldCountry); 146 break; 147 case COUNTRY: 148 final String oldLanguage = mConfig.locale.getLanguage(); 149 mConfig.locale = new Locale(oldLanguage, value); 150 break; 151 default: 152 assert(false); 153 break; 154 } 155 } 156 157 public Resources getResources() { 158 final AssetManager assmgr = new AssetManager(); 159 assmgr.addAssetPath(mContext.getPackageResourcePath()); 160 return new Resources(assmgr, mMetrics, mConfig); 161 } 162 } 163 164 private static void checkPair(Resources res, int[] notResIds, 165 int simpleRes, String simpleString, 166 int bagRes, String bagString) { 167 boolean willHave = true; 168 if (notResIds != null) { 169 for (int i : notResIds) { 170 if (i == simpleRes) { 171 willHave = false; 172 break; 173 } 174 } 175 } 176 checkValue(res, simpleRes, willHave ? simpleString : null); 177 checkValue(res, bagRes, R.styleable.TestConfig, 178 new String[]{willHave ? bagString : null}); 179 } 180 181 @SmallTest 182 public void testAllConfigs() { 183 /** 184 * Test a resource that contains a value for each possible single 185 * configuration value. 186 */ 187 TotalConfig config = new TotalConfig(); 188 Resources res = config.getResources(); 189 checkValue(res, R.configVarying.simple, "simple default"); 190 checkValue(res, R.configVarying.bag, 191 R.styleable.TestConfig, new String[]{"bag default"}); 192 193 config = new TotalConfig(); 194 config.setProperty(Properties.LANGUAGE, "xx"); 195 res = config.getResources(); 196 checkValue(res, R.configVarying.simple, "simple xx"); 197 checkValue(res, R.configVarying.bag, 198 R.styleable.TestConfig, new String[]{"bag xx"}); 199 200 config = new TotalConfig(); 201 config.setProperty(Properties.LANGUAGE, "xx"); 202 config.setProperty(Properties.COUNTRY, "YY"); 203 res = config.getResources(); 204 checkValue(res, R.configVarying.simple, "simple xx-rYY"); 205 checkValue(res, R.configVarying.bag, 206 R.styleable.TestConfig, new String[]{"bag xx-rYY"}); 207 208 config = new TotalConfig(); 209 config.setProperty(Properties.MCC, 111); 210 res = config.getResources(); 211 checkValue(res, R.configVarying.simple, "simple mcc111"); 212 checkValue(res, R.configVarying.bag, 213 R.styleable.TestConfig, new String[]{"bag mcc111"}); 214 215 config = new TotalConfig(); 216 config.setProperty(Properties.MNC, 222); 217 res = config.getResources(); 218 checkValue(res, R.configVarying.simple, "simple mnc222"); 219 checkValue(res, R.configVarying.bag, 220 R.styleable.TestConfig, new String[]{"bag mnc222"}); 221 222 config = new TotalConfig(); 223 config.setProperty(Properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_NOTOUCH); 224 res = config.getResources(); 225 checkValue(res, R.configVarying.simple, "simple notouch"); 226 checkValue(res, R.configVarying.bag, 227 R.styleable.TestConfig, new String[]{"bag notouch"}); 228 229 config = new TotalConfig(); 230 config.setProperty(Properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); 231 res = config.getResources(); 232 checkValue(res, R.configVarying.simple, "simple stylus"); 233 checkValue(res, R.configVarying.bag, 234 R.styleable.TestConfig, new String[]{"bag stylus"}); 235 236 config = new TotalConfig(); 237 config.setProperty(Properties.KEYBOARD, Configuration.KEYBOARD_NOKEYS); 238 res = config.getResources(); 239 checkValue(res, R.configVarying.simple, "simple nokeys"); 240 checkValue(res, R.configVarying.bag, 241 R.styleable.TestConfig, new String[]{"bag nokeys"}); 242 243 config = new TotalConfig(); 244 config.setProperty(Properties.KEYBOARD, Configuration.KEYBOARD_12KEY); 245 res = config.getResources(); 246 checkValue(res, R.configVarying.simple, "simple 12key"); 247 checkValue(res, R.configVarying.bag, 248 R.styleable.TestConfig, new String[]{"bag 12key"}); 249 250 config = new TotalConfig(); 251 config.setProperty(Properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); 252 res = config.getResources(); 253 checkValue(res, R.configVarying.simple, "simple keysexposed"); 254 checkValue(res, R.configVarying.bag, 255 R.styleable.TestConfig, new String[]{"bag keysexposed"}); 256 257 config = new TotalConfig(); 258 config.setProperty(Properties.NAVIGATION, Configuration.NAVIGATION_NONAV); 259 res = config.getResources(); 260 checkValue(res, R.configVarying.simple, "simple nonav"); 261 checkValue(res, R.configVarying.bag, 262 R.styleable.TestConfig, new String[]{"bag nonav"}); 263 264 config = new TotalConfig(); 265 config.setProperty(Properties.NAVIGATION, Configuration.NAVIGATION_DPAD); 266 res = config.getResources(); 267 checkValue(res, R.configVarying.simple, "simple dpad"); 268 checkValue(res, R.configVarying.bag, 269 R.styleable.TestConfig, new String[]{"bag dpad"}); 270 271 config = new TotalConfig(); 272 config.setProperty(Properties.NAVIGATION, Configuration.NAVIGATION_WHEEL); 273 res = config.getResources(); 274 checkValue(res, R.configVarying.simple, "simple wheel"); 275 checkValue(res, R.configVarying.bag, 276 R.styleable.TestConfig, new String[]{"bag wheel"}); 277 278 config = new TotalConfig(); 279 config.setProperty(Properties.HEIGHT, 480); 280 config.setProperty(Properties.WIDTH, 320); 281 res = config.getResources(); 282 checkValue(res, R.configVarying.simple, "simple 480x320"); 283 checkValue(res, R.configVarying.bag, 284 R.styleable.TestConfig, new String[]{"bag 480x320"}); 285 286 config = new TotalConfig(); 287 config.setProperty(Properties.DENSITY, 240); 288 res = config.getResources(); 289 checkValue(res, R.configVarying.simple, "simple 240dpi"); 290 checkValue(res, R.configVarying.bag, 291 R.styleable.TestConfig, new String[]{"bag 240dpi"}); 292 293 config = new TotalConfig(); 294 config.setProperty(Properties.ORIENTATION, Configuration.ORIENTATION_LANDSCAPE); 295 res = config.getResources(); 296 checkValue(res, R.configVarying.simple, "simple landscape"); 297 checkValue(res, R.configVarying.bag, 298 R.styleable.TestConfig, new String[]{"bag landscape"}); 299 300 config = new TotalConfig(); 301 config.setProperty(Properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); 302 res = config.getResources(); 303 checkValue(res, R.configVarying.simple, "simple square"); 304 checkValue(res, R.configVarying.bag, 305 R.styleable.TestConfig, new String[]{"bag square"}); 306 } 307 308 @MediumTest 309 public void testDensity() throws Exception { 310 // have 32, 240 and the default 160 content. 311 // rule is that closest wins, with down scaling (larger content) 312 // being twice as nice as upscaling. 313 // transition at H/2 * (-1 +/- sqrt(1+8L/H)) 314 // SO, X < 49 goes to 32 315 // 49 >= X < 182 goes to 160 316 // X >= 182 goes to 240 317 TotalConfig config = new TotalConfig(); 318 config.setProperty(Properties.DENSITY, 2); 319 Resources res = config.getResources(); 320 checkValue(res, R.configVarying.simple, "simple 32dpi"); 321 checkValue(res, R.configVarying.bag, 322 R.styleable.TestConfig, new String[]{"bag 32dpi"}); 323 324 config = new TotalConfig(); 325 config.setProperty(Properties.DENSITY, 32); 326 res = config.getResources(); 327 checkValue(res, R.configVarying.simple, "simple 32dpi"); 328 checkValue(res, R.configVarying.bag, 329 R.styleable.TestConfig, new String[]{"bag 32dpi"}); 330 331 config = new TotalConfig(); 332 config.setProperty(Properties.DENSITY, 48); 333 res = config.getResources(); 334 checkValue(res, R.configVarying.simple, "simple 32dpi"); 335 checkValue(res, R.configVarying.bag, 336 R.styleable.TestConfig, new String[]{"bag 32dpi"}); 337 338 config = new TotalConfig(); 339 config.setProperty(Properties.DENSITY, 49); 340 res = config.getResources(); 341 checkValue(res, R.configVarying.simple, "simple default"); 342 checkValue(res, R.configVarying.bag, 343 R.styleable.TestConfig, new String[]{"bag default"}); 344 345 config = new TotalConfig(); 346 config.setProperty(Properties.DENSITY, 150); 347 res = config.getResources(); 348 checkValue(res, R.configVarying.simple, "simple default"); 349 checkValue(res, R.configVarying.bag, 350 R.styleable.TestConfig, new String[]{"bag default"}); 351 352 config = new TotalConfig(); 353 config.setProperty(Properties.DENSITY, 181); 354 res = config.getResources(); 355 checkValue(res, R.configVarying.simple, "simple default"); 356 checkValue(res, R.configVarying.bag, 357 R.styleable.TestConfig, new String[]{"bag default"}); 358 359 config = new TotalConfig(); 360 config.setProperty(Properties.DENSITY, 182); 361 res = config.getResources(); 362 checkValue(res, R.configVarying.simple, "simple 240dpi"); 363 checkValue(res, R.configVarying.bag, 364 R.styleable.TestConfig, new String[]{"bag 240dpi"}); 365 366 config = new TotalConfig(); 367 config.setProperty(Properties.DENSITY, 239); 368 res = config.getResources(); 369 checkValue(res, R.configVarying.simple, "simple 240dpi"); 370 checkValue(res, R.configVarying.bag, 371 R.styleable.TestConfig, new String[]{"bag 240dpi"}); 372 373 config = new TotalConfig(); 374 config.setProperty(Properties.DENSITY, 490); 375 res = config.getResources(); 376 checkValue(res, R.configVarying.simple, "simple 240dpi"); 377 checkValue(res, R.configVarying.bag, 378 R.styleable.TestConfig, new String[]{"bag 240dpi"}); 379 } 380 381 // TODO - add tests for special cases - ie, other key params seem ignored if 382 // nokeys is set 383 384 @MediumTest 385 public void testCombinations() { 386 /** 387 * Verify that proper strings are found for multiple-selectivity case 388 * (ie, a string set for locale and mcc is found only when both are 389 * true). 390 */ 391 TotalConfig config = new TotalConfig(); 392 config.setProperty(Properties.LANGUAGE, "xx"); 393 config.setProperty(Properties.COUNTRY, "YY"); 394 config.setProperty(Properties.MCC, 111); 395 Resources res = config.getResources(); 396 checkValue(res, R.configVarying.simple, "simple mcc111 xx-rYY"); 397 checkValue(res, R.configVarying.bag, R.styleable.TestConfig, 398 new String[] { "bag mcc111 xx-rYY" }); 399 400 config = new TotalConfig(); 401 config.setProperty(Properties.LANGUAGE, "xx"); 402 config.setProperty(Properties.COUNTRY, "YY"); 403 config.setProperty(Properties.MCC, 333); 404 res = config.getResources(); 405 checkValue(res, R.configVarying.simple, "simple xx-rYY"); 406 checkValue(res, R.configVarying.bag, 407 R.styleable.TestConfig, new String[] { "bag xx-rYY" }); 408 409 config = new TotalConfig(); 410 config.setProperty(Properties.MNC, 333); 411 res = config.getResources(); 412 checkValue(res, R.configVarying.simple, "simple default"); 413 checkValue(res, R.configVarying.bag, 414 R.styleable.TestConfig, new String[]{"bag default"}); 415 } 416 417 @MediumTest 418 public void testPrecidence() { 419 /** 420 * Verify that in cases of ties, the specific ordering is followed 421 */ 422 423 /** 424 * Precidence order: mcc, mnc, locale, orientation, density, 425 * touchscreen, hidden, keyboard, navigation, width-height 426 */ 427 428 /** 429 * verify mcc trumps mnc. Have 110-xx, 220-xx but no 110-220 430 * so with is selected? Should be mcc110-xx. 431 */ 432 TotalConfig config = new TotalConfig(); 433 config.setProperty(Properties.MCC, 110); 434 config.setProperty(Properties.MNC, 220); 435 config.setProperty(Properties.LANGUAGE, "xx"); 436 Resources res = config.getResources(); 437 checkValue(res, R.configVarying.simple, "simple mcc110 xx"); 438 checkValue(res, R.configVarying.bag, 439 R.styleable.TestConfig, new String[]{"bag mcc110 xx"}); 440 441 /* full A + B + C doesn't exist. Do we get A + C or B + C? 442 */ 443 config = new TotalConfig(); 444 config.setProperty(Properties.MCC, 111); 445 config.setProperty(Properties.MNC, 222); 446 config.setProperty(Properties.LANGUAGE, "xx"); 447 res = config.getResources(); 448 checkValue(res, R.configVarying.simple, "simple mcc111 mnc222"); 449 checkValue(res, R.configVarying.bag, 450 R.styleable.TestConfig, new String[]{"bag mcc111 mnc222"}); 451 452 config = new TotalConfig(); 453 config.setProperty(Properties.MNC, 222); 454 config.setProperty(Properties.LANGUAGE, "xx"); 455 config.setProperty(Properties.ORIENTATION, 456 Configuration.ORIENTATION_SQUARE); 457 res = config.getResources(); 458 checkValue(res, R.configVarying.simple, "simple mnc222 xx"); 459 checkValue(res, R.configVarying.bag, 460 R.styleable.TestConfig, new String[]{"bag mnc222 xx"}); 461 462 config = new TotalConfig(); 463 config.setProperty(Properties.LANGUAGE, "xx"); 464 config.setProperty(Properties.ORIENTATION, 465 Configuration.ORIENTATION_SQUARE); 466 config.setProperty(Properties.DENSITY, 32); 467 res = config.getResources(); 468 checkValue(res, R.configVarying.simple, "simple xx square"); 469 checkValue(res, R.configVarying.bag, 470 R.styleable.TestConfig, new String[]{"bag xx square"}); 471 472 config = new TotalConfig(); 473 config.setProperty(Properties.ORIENTATION, 474 Configuration.ORIENTATION_SQUARE); 475 config.setProperty(Properties.DENSITY, 32); 476 config.setProperty(Properties.TOUCHSCREEN, 477 Configuration.TOUCHSCREEN_STYLUS); 478 res = config.getResources(); 479 checkValue(res, R.configVarying.simple, "simple square 32dpi"); 480 checkValue(res, R.configVarying.bag, 481 R.styleable.TestConfig, new String[]{"bag square 32dpi"}); 482 483 config = new TotalConfig(); 484 config.setProperty(Properties.DENSITY, 32); 485 config.setProperty(Properties.TOUCHSCREEN, 486 Configuration.TOUCHSCREEN_STYLUS); 487 config.setProperty(Properties.KEYBOARDHIDDEN, 488 Configuration.KEYBOARDHIDDEN_NO); 489 res = config.getResources(); 490 checkValue(res, R.configVarying.simple, "simple 32dpi stylus"); 491 checkValue(res, R.configVarying.bag, 492 R.styleable.TestConfig, new String[]{"bag 32dpi stylus"}); 493 494 config = new TotalConfig(); 495 config.setProperty(Properties.TOUCHSCREEN, 496 Configuration.TOUCHSCREEN_STYLUS); 497 config.setProperty(Properties.KEYBOARDHIDDEN, 498 Configuration.KEYBOARDHIDDEN_NO); 499 config.setProperty(Properties.KEYBOARD, Configuration.KEYBOARD_12KEY); 500 res = config.getResources(); 501 checkValue(res, R.configVarying.simple, "simple stylus keysexposed"); 502 checkValue(res, R.configVarying.bag, 503 R.styleable.TestConfig, new String[]{"bag stylus keysexposed"}); 504 505 config = new TotalConfig(); 506 config.setProperty(Properties.KEYBOARDHIDDEN, 507 Configuration.KEYBOARDHIDDEN_NO); 508 config.setProperty(Properties.KEYBOARD, Configuration.KEYBOARD_12KEY); 509 config.setProperty(Properties.NAVIGATION, 510 Configuration.NAVIGATION_DPAD); 511 res = config.getResources(); 512 checkValue(res, R.configVarying.simple, "simple keysexposed 12key"); 513 checkValue(res, R.configVarying.bag, 514 R.styleable.TestConfig, new String[]{"bag keysexposed 12key"}); 515 516 config = new TotalConfig(); 517 config.setProperty(Properties.KEYBOARD, Configuration.KEYBOARD_12KEY); 518 config.setProperty(Properties.NAVIGATION, 519 Configuration.NAVIGATION_DPAD); 520 config.setProperty(Properties.HEIGHT, 63); 521 config.setProperty(Properties.WIDTH, 57); 522 res = config.getResources(); 523 checkValue(res, R.configVarying.simple, "simple 12key dpad"); 524 checkValue(res, R.configVarying.bag, 525 R.styleable.TestConfig, new String[]{"bag 12key dpad"}); 526 527 config = new TotalConfig(); 528 config.setProperty(Properties.NAVIGATION, 529 Configuration.NAVIGATION_DPAD); 530 config.setProperty(Properties.HEIGHT, 640); 531 config.setProperty(Properties.WIDTH, 400); 532 res = config.getResources(); 533 checkValue(res, R.configVarying.simple, "simple dpad"); 534 checkValue(res, R.configVarying.bag, 535 R.styleable.TestConfig, new String[]{"bag dpad"}); 536 } 537 538 @MediumTest 539 public void testVersions() { 540 // Check that we get the most recent resources that are <= our 541 // current version. Note the special version adjustment, so that 542 // during development the resource version is incremented to the 543 // next one. 544 int vers = android.os.Build.VERSION.SDK_INT; 545 if (!"REL".equals(android.os.Build.VERSION.CODENAME)) { 546 vers++; 547 } 548 String expected = "v" + vers + "cur"; 549 assertEquals(expected, mContext.getResources().getString(R.string.version_cur)); 550 assertEquals("base", mContext.getResources().getString(R.string.version_old)); 551 assertEquals("v3", mContext.getResources().getString(R.string.version_v3)); 552 } 553 } 554