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