1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php 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.ide.eclipse.adt.internal.resources.configurations; 18 19 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType; 20 21 22 /** 23 * Represents the configuration for Resource Folders. All the properties have a default 24 * value which means that the property is not set. 25 */ 26 public final class FolderConfiguration implements Comparable<FolderConfiguration> { 27 public final static String QUALIFIER_SEP = "-"; //$NON-NLS-1$ 28 29 private final ResourceQualifier[] mQualifiers = new ResourceQualifier[INDEX_COUNT]; 30 31 private final static int INDEX_COUNTRY_CODE = 0; 32 private final static int INDEX_NETWORK_CODE = 1; 33 private final static int INDEX_LANGUAGE = 2; 34 private final static int INDEX_REGION = 3; 35 private final static int INDEX_SCREEN_SIZE = 4; 36 private final static int INDEX_SCREEN_RATIO = 5; 37 private final static int INDEX_SCREEN_ORIENTATION = 6; 38 private final static int INDEX_DOCK_MODE = 7; 39 private final static int INDEX_NIGHT_MODE = 8; 40 private final static int INDEX_PIXEL_DENSITY = 9; 41 private final static int INDEX_TOUCH_TYPE = 10; 42 private final static int INDEX_KEYBOARD_STATE = 11; 43 private final static int INDEX_TEXT_INPUT_METHOD = 12; 44 private final static int INDEX_NAVIGATION_STATE = 14; 45 private final static int INDEX_NAVIGATION_METHOD = 15; 46 private final static int INDEX_SCREEN_DIMENSION = 16; 47 private final static int INDEX_VERSION = 17; 48 private final static int INDEX_COUNT = 18; 49 50 /** 51 * Returns the number of {@link ResourceQualifier} that make up a Folder configuration. 52 */ 53 public static int getQualifierCount() { 54 return INDEX_COUNT; 55 } 56 57 /** 58 * Sets the config from the qualifiers of a given <var>config</var>. 59 * <p/>This is equivalent to <code>set(config, false)</code> 60 * @param config the configuration to set 61 * 62 * @see #set(FolderConfiguration, boolean) 63 */ 64 public void set(FolderConfiguration config) { 65 set(config, false /*nonFakeValuesOnly*/); 66 } 67 68 /** 69 * Sets the config from the qualifiers of a given <var>config</var>. 70 * @param config the configuration to set 71 * @param nonFakeValuesOnly if set to true this ignore qualifiers for which the 72 * current value is a fake value. 73 * 74 * @see ResourceQualifier#hasFakeValue() 75 */ 76 public void set(FolderConfiguration config, boolean nonFakeValuesOnly) { 77 if (config != null) { 78 for (int i = 0 ; i < INDEX_COUNT ; i++) { 79 ResourceQualifier q = config.mQualifiers[i]; 80 if (nonFakeValuesOnly == false || q == null || q.hasFakeValue() == false) { 81 mQualifiers[i] = q; 82 } 83 } 84 } 85 } 86 87 /** 88 * Removes the qualifiers from the receiver if they are present (and valid) 89 * in the given configuration. 90 */ 91 public void substract(FolderConfiguration config) { 92 for (int i = 0 ; i < INDEX_COUNT ; i++) { 93 if (config.mQualifiers[i] != null && config.mQualifiers[i].isValid()) { 94 mQualifiers[i] = null; 95 } 96 } 97 } 98 99 /** 100 * Returns the first invalid qualifier, or <code>null<code> if they are all valid (or if none 101 * exists). 102 */ 103 public ResourceQualifier getInvalidQualifier() { 104 for (int i = 0 ; i < INDEX_COUNT ; i++) { 105 if (mQualifiers[i] != null && mQualifiers[i].isValid() == false) { 106 return mQualifiers[i]; 107 } 108 } 109 110 // all allocated qualifiers are valid, we return null. 111 return null; 112 } 113 114 /** 115 * Returns whether the Region qualifier is valid. Region qualifier can only be present if a 116 * Language qualifier is present as well. 117 * @return true if the Region qualifier is valid. 118 */ 119 public boolean checkRegion() { 120 if (mQualifiers[INDEX_LANGUAGE] == null && mQualifiers[INDEX_REGION] != null) { 121 return false; 122 } 123 124 return true; 125 } 126 127 /** 128 * Adds a qualifier to the {@link FolderConfiguration} 129 * @param qualifier the {@link ResourceQualifier} to add. 130 */ 131 public void addQualifier(ResourceQualifier qualifier) { 132 if (qualifier instanceof CountryCodeQualifier) { 133 mQualifiers[INDEX_COUNTRY_CODE] = qualifier; 134 } else if (qualifier instanceof NetworkCodeQualifier) { 135 mQualifiers[INDEX_NETWORK_CODE] = qualifier; 136 } else if (qualifier instanceof LanguageQualifier) { 137 mQualifiers[INDEX_LANGUAGE] = qualifier; 138 } else if (qualifier instanceof RegionQualifier) { 139 mQualifiers[INDEX_REGION] = qualifier; 140 } else if (qualifier instanceof ScreenSizeQualifier) { 141 mQualifiers[INDEX_SCREEN_SIZE] = qualifier; 142 } else if (qualifier instanceof ScreenRatioQualifier) { 143 mQualifiers[INDEX_SCREEN_RATIO] = qualifier; 144 } else if (qualifier instanceof ScreenOrientationQualifier) { 145 mQualifiers[INDEX_SCREEN_ORIENTATION] = qualifier; 146 } else if (qualifier instanceof DockModeQualifier) { 147 mQualifiers[INDEX_DOCK_MODE] = qualifier; 148 } else if (qualifier instanceof NightModeQualifier) { 149 mQualifiers[INDEX_NIGHT_MODE] = qualifier; 150 } else if (qualifier instanceof PixelDensityQualifier) { 151 mQualifiers[INDEX_PIXEL_DENSITY] = qualifier; 152 } else if (qualifier instanceof TouchScreenQualifier) { 153 mQualifiers[INDEX_TOUCH_TYPE] = qualifier; 154 } else if (qualifier instanceof KeyboardStateQualifier) { 155 mQualifiers[INDEX_KEYBOARD_STATE] = qualifier; 156 } else if (qualifier instanceof TextInputMethodQualifier) { 157 mQualifiers[INDEX_TEXT_INPUT_METHOD] = qualifier; 158 } else if (qualifier instanceof NavigationStateQualifier) { 159 mQualifiers[INDEX_NAVIGATION_STATE] = qualifier; 160 } else if (qualifier instanceof NavigationMethodQualifier) { 161 mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier; 162 } else if (qualifier instanceof ScreenDimensionQualifier) { 163 mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier; 164 } else if (qualifier instanceof VersionQualifier) { 165 mQualifiers[INDEX_VERSION] = qualifier; 166 } 167 } 168 169 /** 170 * Removes a given qualifier from the {@link FolderConfiguration}. 171 * @param qualifier the {@link ResourceQualifier} to remove. 172 */ 173 public void removeQualifier(ResourceQualifier qualifier) { 174 for (int i = 0 ; i < INDEX_COUNT ; i++) { 175 if (mQualifiers[i] == qualifier) { 176 mQualifiers[i] = null; 177 return; 178 } 179 } 180 } 181 182 /** 183 * Returns a qualifier by its index. The total number of qualifiers can be accessed by 184 * {@link #getQualifierCount()}. 185 * @param index the index of the qualifier to return. 186 * @return the qualifier or null if there are none at the index. 187 */ 188 public ResourceQualifier getQualifier(int index) { 189 return mQualifiers[index]; 190 } 191 192 public void setCountryCodeQualifier(CountryCodeQualifier qualifier) { 193 mQualifiers[INDEX_COUNTRY_CODE] = qualifier; 194 } 195 196 public CountryCodeQualifier getCountryCodeQualifier() { 197 return (CountryCodeQualifier)mQualifiers[INDEX_COUNTRY_CODE]; 198 } 199 200 public void setNetworkCodeQualifier(NetworkCodeQualifier qualifier) { 201 mQualifiers[INDEX_NETWORK_CODE] = qualifier; 202 } 203 204 public NetworkCodeQualifier getNetworkCodeQualifier() { 205 return (NetworkCodeQualifier)mQualifiers[INDEX_NETWORK_CODE]; 206 } 207 208 public void setLanguageQualifier(LanguageQualifier qualifier) { 209 mQualifiers[INDEX_LANGUAGE] = qualifier; 210 } 211 212 public LanguageQualifier getLanguageQualifier() { 213 return (LanguageQualifier)mQualifiers[INDEX_LANGUAGE]; 214 } 215 216 public void setRegionQualifier(RegionQualifier qualifier) { 217 mQualifiers[INDEX_REGION] = qualifier; 218 } 219 220 public RegionQualifier getRegionQualifier() { 221 return (RegionQualifier)mQualifiers[INDEX_REGION]; 222 } 223 224 public void setScreenSizeQualifier(ScreenSizeQualifier qualifier) { 225 mQualifiers[INDEX_SCREEN_SIZE] = qualifier; 226 } 227 228 public ScreenSizeQualifier getScreenSizeQualifier() { 229 return (ScreenSizeQualifier)mQualifiers[INDEX_SCREEN_SIZE]; 230 } 231 232 public void setScreenRatioQualifier(ScreenRatioQualifier qualifier) { 233 mQualifiers[INDEX_SCREEN_RATIO] = qualifier; 234 } 235 236 public ScreenRatioQualifier getScreenRatioQualifier() { 237 return (ScreenRatioQualifier)mQualifiers[INDEX_SCREEN_RATIO]; 238 } 239 240 public void setScreenOrientationQualifier(ScreenOrientationQualifier qualifier) { 241 mQualifiers[INDEX_SCREEN_ORIENTATION] = qualifier; 242 } 243 244 public ScreenOrientationQualifier getScreenOrientationQualifier() { 245 return (ScreenOrientationQualifier)mQualifiers[INDEX_SCREEN_ORIENTATION]; 246 } 247 248 public void setDockModeQualifier(DockModeQualifier qualifier) { 249 mQualifiers[INDEX_DOCK_MODE] = qualifier; 250 } 251 252 public DockModeQualifier getDockModeQualifier() { 253 return (DockModeQualifier)mQualifiers[INDEX_DOCK_MODE]; 254 } 255 256 public void setNightModeQualifier(NightModeQualifier qualifier) { 257 mQualifiers[INDEX_NIGHT_MODE] = qualifier; 258 } 259 260 public NightModeQualifier getNightModeQualifier() { 261 return (NightModeQualifier)mQualifiers[INDEX_NIGHT_MODE]; 262 } 263 264 public void setPixelDensityQualifier(PixelDensityQualifier qualifier) { 265 mQualifiers[INDEX_PIXEL_DENSITY] = qualifier; 266 } 267 268 public PixelDensityQualifier getPixelDensityQualifier() { 269 return (PixelDensityQualifier)mQualifiers[INDEX_PIXEL_DENSITY]; 270 } 271 272 public void setTouchTypeQualifier(TouchScreenQualifier qualifier) { 273 mQualifiers[INDEX_TOUCH_TYPE] = qualifier; 274 } 275 276 public TouchScreenQualifier getTouchTypeQualifier() { 277 return (TouchScreenQualifier)mQualifiers[INDEX_TOUCH_TYPE]; 278 } 279 280 public void setKeyboardStateQualifier(KeyboardStateQualifier qualifier) { 281 mQualifiers[INDEX_KEYBOARD_STATE] = qualifier; 282 } 283 284 public KeyboardStateQualifier getKeyboardStateQualifier() { 285 return (KeyboardStateQualifier)mQualifiers[INDEX_KEYBOARD_STATE]; 286 } 287 288 public void setTextInputMethodQualifier(TextInputMethodQualifier qualifier) { 289 mQualifiers[INDEX_TEXT_INPUT_METHOD] = qualifier; 290 } 291 292 public TextInputMethodQualifier getTextInputMethodQualifier() { 293 return (TextInputMethodQualifier)mQualifiers[INDEX_TEXT_INPUT_METHOD]; 294 } 295 296 public void setNavigationStateQualifier(NavigationStateQualifier qualifier) { 297 mQualifiers[INDEX_NAVIGATION_STATE] = qualifier; 298 } 299 300 public NavigationStateQualifier getNavigationStateQualifier() { 301 return (NavigationStateQualifier)mQualifiers[INDEX_NAVIGATION_STATE]; 302 } 303 304 public void setNavigationMethodQualifier(NavigationMethodQualifier qualifier) { 305 mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier; 306 } 307 308 public NavigationMethodQualifier getNavigationMethodQualifier() { 309 return (NavigationMethodQualifier)mQualifiers[INDEX_NAVIGATION_METHOD]; 310 } 311 312 public void setScreenDimensionQualifier(ScreenDimensionQualifier qualifier) { 313 mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier; 314 } 315 316 public ScreenDimensionQualifier getScreenDimensionQualifier() { 317 return (ScreenDimensionQualifier)mQualifiers[INDEX_SCREEN_DIMENSION]; 318 } 319 320 public void setVersionQualifier(VersionQualifier qualifier) { 321 mQualifiers[INDEX_VERSION] = qualifier; 322 } 323 324 public VersionQualifier getVersionQualifier() { 325 return (VersionQualifier)mQualifiers[INDEX_VERSION]; 326 } 327 328 /** 329 * Returns whether an object is equals to the receiver. 330 */ 331 @Override 332 public boolean equals(Object obj) { 333 if (obj == this) { 334 return true; 335 } 336 337 if (obj instanceof FolderConfiguration) { 338 FolderConfiguration fc = (FolderConfiguration)obj; 339 for (int i = 0 ; i < INDEX_COUNT ; i++) { 340 ResourceQualifier qualifier = mQualifiers[i]; 341 ResourceQualifier fcQualifier = fc.mQualifiers[i]; 342 if (qualifier != null) { 343 if (qualifier.equals(fcQualifier) == false) { 344 return false; 345 } 346 } else if (fcQualifier != null) { 347 return false; 348 } 349 } 350 351 return true; 352 } 353 354 return false; 355 } 356 357 @Override 358 public int hashCode() { 359 return toString().hashCode(); 360 } 361 362 /** 363 * Returns whether the Configuration has only default values. 364 */ 365 public boolean isDefault() { 366 for (ResourceQualifier irq : mQualifiers) { 367 if (irq != null) { 368 return false; 369 } 370 } 371 372 return true; 373 } 374 375 /** 376 * Returns the name of a folder with the configuration. 377 */ 378 public String getFolderName(ResourceFolderType folder) { 379 StringBuilder result = new StringBuilder(folder.getName()); 380 381 for (ResourceQualifier qualifier : mQualifiers) { 382 if (qualifier != null) { 383 String segment = qualifier.getFolderSegment(); 384 if (segment != null && segment.length() > 0) { 385 result.append(QUALIFIER_SEP); 386 result.append(segment); 387 } 388 } 389 } 390 391 return result.toString(); 392 } 393 394 /** 395 * Returns {@link #toDisplayString()}. 396 */ 397 @Override 398 public String toString() { 399 return toDisplayString(); 400 } 401 402 /** 403 * Returns a string valid for display purpose. 404 */ 405 public String toDisplayString() { 406 if (isDefault()) { 407 return "default"; 408 } 409 410 StringBuilder result = null; 411 int index = 0; 412 ResourceQualifier qualifier = null; 413 414 // pre- language/region qualifiers 415 while (index < INDEX_LANGUAGE) { 416 qualifier = mQualifiers[index++]; 417 if (qualifier != null) { 418 if (result == null) { 419 result = new StringBuilder(); 420 } else { 421 result.append(", "); //$NON-NLS-1$ 422 } 423 result.append(qualifier.getLongDisplayValue()); 424 425 } 426 } 427 428 // process the language/region qualifier in a custom way, if there are both non null. 429 if (mQualifiers[INDEX_LANGUAGE] != null && mQualifiers[INDEX_REGION] != null) { 430 String language = mQualifiers[INDEX_LANGUAGE].getLongDisplayValue(); 431 String region = mQualifiers[INDEX_REGION].getLongDisplayValue(); 432 433 if (result == null) { 434 result = new StringBuilder(); 435 } else { 436 result.append(", "); //$NON-NLS-1$ 437 } 438 result.append(String.format("Locale %s_%s", language, region)); //$NON-NLS-1$ 439 440 index += 2; 441 } 442 443 // post language/region qualifiers. 444 while (index < INDEX_COUNT) { 445 qualifier = mQualifiers[index++]; 446 if (qualifier != null) { 447 if (result == null) { 448 result = new StringBuilder(); 449 } else { 450 result.append(", "); //$NON-NLS-1$ 451 } 452 result.append(qualifier.getLongDisplayValue()); 453 454 } 455 } 456 457 return result == null ? null : result.toString(); 458 } 459 460 public int compareTo(FolderConfiguration folderConfig) { 461 // default are always at the top. 462 if (isDefault()) { 463 if (folderConfig.isDefault()) { 464 return 0; 465 } 466 return -1; 467 } 468 469 // now we compare the qualifiers 470 for (int i = 0 ; i < INDEX_COUNT; i++) { 471 ResourceQualifier qualifier1 = mQualifiers[i]; 472 ResourceQualifier qualifier2 = folderConfig.mQualifiers[i]; 473 474 if (qualifier1 == null) { 475 if (qualifier2 == null) { 476 continue; 477 } else { 478 return -1; 479 } 480 } else { 481 if (qualifier2 == null) { 482 return 1; 483 } else { 484 int result = qualifier1.compareTo(qualifier2); 485 486 if (result == 0) { 487 continue; 488 } 489 490 return result; 491 } 492 } 493 } 494 495 // if we arrive here, all the qualifier matches 496 return 0; 497 } 498 499 /** 500 * Returns whether the configuration is a match for the given reference config. 501 * <p/>A match means that, for each qualifier of this config 502 * <ul> 503 * <li>The reference config has no value set 504 * <li>or, the qualifier of the reference config is a match. Depending on the qualifier type 505 * this does not mean the same exact value.</li> 506 * </ul> 507 * @param referenceConfig The reference configuration to test against. 508 * @return true if the configuration matches. 509 */ 510 public boolean isMatchFor(FolderConfiguration referenceConfig) { 511 for (int i = 0 ; i < INDEX_COUNT ; i++) { 512 ResourceQualifier testQualifier = mQualifiers[i]; 513 ResourceQualifier referenceQualifier = referenceConfig.mQualifiers[i]; 514 515 // it's only a non match if both qualifiers are non-null, and they don't match. 516 if (testQualifier != null && referenceQualifier != null && 517 testQualifier.isMatchFor(referenceQualifier) == false) { 518 return false; 519 } 520 } 521 return true; 522 } 523 524 /** 525 * Returns the index of the first non null {@link ResourceQualifier} starting at index 526 * <var>startIndex</var> 527 * @param startIndex 528 * @return -1 if no qualifier was found. 529 */ 530 public int getHighestPriorityQualifier(int startIndex) { 531 for (int i = startIndex ; i < INDEX_COUNT ; i++) { 532 if (mQualifiers[i] != null) { 533 return i; 534 } 535 } 536 537 return -1; 538 } 539 540 /** 541 * Create default qualifiers. 542 */ 543 public void createDefault() { 544 mQualifiers[INDEX_COUNTRY_CODE] = new CountryCodeQualifier(); 545 mQualifiers[INDEX_NETWORK_CODE] = new NetworkCodeQualifier(); 546 mQualifiers[INDEX_LANGUAGE] = new LanguageQualifier(); 547 mQualifiers[INDEX_REGION] = new RegionQualifier(); 548 mQualifiers[INDEX_SCREEN_SIZE] = new ScreenSizeQualifier(); 549 mQualifiers[INDEX_SCREEN_RATIO] = new ScreenRatioQualifier(); 550 mQualifiers[INDEX_SCREEN_ORIENTATION] = new ScreenOrientationQualifier(); 551 mQualifiers[INDEX_DOCK_MODE] = new DockModeQualifier(); 552 mQualifiers[INDEX_NIGHT_MODE] = new NightModeQualifier(); 553 mQualifiers[INDEX_PIXEL_DENSITY] = new PixelDensityQualifier(); 554 mQualifiers[INDEX_TOUCH_TYPE] = new TouchScreenQualifier(); 555 mQualifiers[INDEX_KEYBOARD_STATE] = new KeyboardStateQualifier(); 556 mQualifiers[INDEX_TEXT_INPUT_METHOD] = new TextInputMethodQualifier(); 557 mQualifiers[INDEX_NAVIGATION_STATE] = new NavigationStateQualifier(); 558 mQualifiers[INDEX_NAVIGATION_METHOD] = new NavigationMethodQualifier(); 559 mQualifiers[INDEX_SCREEN_DIMENSION] = new ScreenDimensionQualifier(); 560 mQualifiers[INDEX_VERSION] = new VersionQualifier(); 561 } 562 563 /** 564 * Returns an array of all the non null qualifiers. 565 */ 566 public ResourceQualifier[] getQualifiers() { 567 int count = 0; 568 for (int i = 0 ; i < INDEX_COUNT ; i++) { 569 if (mQualifiers[i] != null) { 570 count++; 571 } 572 } 573 574 ResourceQualifier[] array = new ResourceQualifier[count]; 575 int index = 0; 576 for (int i = 0 ; i < INDEX_COUNT ; i++) { 577 if (mQualifiers[i] != null) { 578 array[index++] = mQualifiers[i]; 579 } 580 } 581 582 return array; 583 } 584 } 585