1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 /** 3 ******************************************************************************* 4 * Copyright (C) 2001-2015, International Business Machines Corporation and * 5 * others. All Rights Reserved. * 6 ******************************************************************************* 7 */ 8 package android.icu.impl; 9 10 import java.util.Collections; 11 import java.util.Locale; 12 import java.util.Map; 13 import java.util.Set; 14 15 import android.icu.util.ULocale; 16 17 /** 18 * @hide Only a subset of ICU is exposed in Android 19 */ 20 public class ICULocaleService extends ICUService { 21 private ULocale fallbackLocale; 22 private String fallbackLocaleName; 23 24 /** 25 * Construct an ICULocaleService. 26 */ 27 public ICULocaleService() { 28 } 29 30 /** 31 * Construct an ICULocaleService with a name (useful for debugging). 32 */ 33 public ICULocaleService(String name) { 34 super(name); 35 } 36 37 /** 38 * Convenience override for callers using locales. This calls 39 * get(ULocale, int, ULocale[]) with KIND_ANY for kind and null for 40 * actualReturn. 41 */ 42 public Object get(ULocale locale) { 43 return get(locale, LocaleKey.KIND_ANY, null); 44 } 45 46 /** 47 * Convenience override for callers using locales. This calls 48 * get(ULocale, int, ULocale[]) with a null actualReturn. 49 */ 50 public Object get(ULocale locale, int kind) { 51 return get(locale, kind, null); 52 } 53 54 /** 55 * Convenience override for callers using locales. This calls 56 * get(ULocale, int, ULocale[]) with KIND_ANY for kind. 57 */ 58 public Object get(ULocale locale, ULocale[] actualReturn) { 59 return get(locale, LocaleKey.KIND_ANY, actualReturn); 60 } 61 62 /** 63 * Convenience override for callers using locales. This uses 64 * createKey(ULocale.toString(), kind) to create a key, calls getKey, and then 65 * if actualReturn is not null, returns the actualResult from 66 * getKey (stripping any prefix) into a ULocale. 67 */ 68 public Object get(ULocale locale, int kind, ULocale[] actualReturn) { 69 Key key = createKey(locale, kind); 70 if (actualReturn == null) { 71 return getKey(key); 72 } 73 74 String[] temp = new String[1]; 75 Object result = getKey(key, temp); 76 if (result != null) { 77 int n = temp[0].indexOf("/"); 78 if (n >= 0) { 79 temp[0] = temp[0].substring(n+1); 80 } 81 actualReturn[0] = new ULocale(temp[0]); 82 } 83 return result; 84 } 85 86 /** 87 * Convenience override for callers using locales. This calls 88 * registerObject(Object, ULocale, int kind, boolean visible) 89 * passing KIND_ANY for the kind, and true for the visibility. 90 */ 91 public Factory registerObject(Object obj, ULocale locale) { 92 return registerObject(obj, locale, LocaleKey.KIND_ANY, true); 93 } 94 95 /** 96 * Convenience override for callers using locales. This calls 97 * registerObject(Object, ULocale, int kind, boolean visible) 98 * passing KIND_ANY for the kind. 99 */ 100 public Factory registerObject(Object obj, ULocale locale, boolean visible) { 101 return registerObject(obj, locale, LocaleKey.KIND_ANY, visible); 102 } 103 104 /** 105 * Convenience function for callers using locales. This calls 106 * registerObject(Object, ULocale, int kind, boolean visible) 107 * passing true for the visibility. 108 */ 109 public Factory registerObject(Object obj, ULocale locale, int kind) { 110 return registerObject(obj, locale, kind, true); 111 } 112 113 /** 114 * Convenience function for callers using locales. This instantiates 115 * a SimpleLocaleKeyFactory, and registers the factory. 116 */ 117 public Factory registerObject(Object obj, ULocale locale, int kind, boolean visible) { 118 Factory factory = new SimpleLocaleKeyFactory(obj, locale, kind, visible); 119 return registerFactory(factory); 120 } 121 122 /** 123 * Convenience method for callers using locales. This returns the standard 124 * Locale list, built from the Set of visible ids. 125 */ 126 public Locale[] getAvailableLocales() { 127 // TODO make this wrap getAvailableULocales later 128 Set<String> visIDs = getVisibleIDs(); 129 Locale[] locales = new Locale[visIDs.size()]; 130 int n = 0; 131 for (String id : visIDs) { 132 Locale loc = LocaleUtility.getLocaleFromName(id); 133 locales[n++] = loc; 134 } 135 return locales; 136 } 137 138 /** 139 * Convenience method for callers using locales. This returns the standard 140 * ULocale list, built from the Set of visible ids. 141 */ 142 public ULocale[] getAvailableULocales() { 143 Set<String> visIDs = getVisibleIDs(); 144 ULocale[] locales = new ULocale[visIDs.size()]; 145 int n = 0; 146 for (String id : visIDs) { 147 locales[n++] = new ULocale(id); 148 } 149 return locales; 150 } 151 152 /** 153 * A subclass of Key that implements a locale fallback mechanism. 154 * The first locale to search for is the locale provided by the 155 * client, and the fallback locale to search for is the current 156 * default locale. If a prefix is present, the currentDescriptor 157 * includes it before the locale proper, separated by "/". This 158 * is the default key instantiated by ICULocaleService.</p> 159 * 160 * <p>Canonicalization adjusts the locale string so that the 161 * section before the first understore is in lower case, and the rest 162 * is in upper case, with no trailing underscores.</p> 163 */ 164 public static class LocaleKey extends ICUService.Key { 165 private int kind; 166 private int varstart; 167 private String primaryID; 168 private String fallbackID; 169 private String currentID; 170 171 public static final int KIND_ANY = -1; 172 173 /** 174 * Create a LocaleKey with canonical primary and fallback IDs. 175 */ 176 public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID) { 177 return createWithCanonicalFallback(primaryID, canonicalFallbackID, KIND_ANY); 178 } 179 180 /** 181 * Create a LocaleKey with canonical primary and fallback IDs. 182 */ 183 public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID, int kind) { 184 if (primaryID == null) { 185 return null; 186 } 187 String canonicalPrimaryID = ULocale.getName(primaryID); 188 return new LocaleKey(primaryID, canonicalPrimaryID, canonicalFallbackID, kind); 189 } 190 191 /** 192 * Create a LocaleKey with canonical primary and fallback IDs. 193 */ 194 public static LocaleKey createWithCanonical(ULocale locale, String canonicalFallbackID, int kind) { 195 if (locale == null) { 196 return null; 197 } 198 String canonicalPrimaryID = locale.getName(); 199 return new LocaleKey(canonicalPrimaryID, canonicalPrimaryID, canonicalFallbackID, kind); 200 } 201 202 /** 203 * PrimaryID is the user's requested locale string, 204 * canonicalPrimaryID is this string in canonical form, 205 * fallbackID is the current default locale's string in 206 * canonical form. 207 */ 208 protected LocaleKey(String primaryID, String canonicalPrimaryID, String canonicalFallbackID, int kind) { 209 super(primaryID); 210 this.kind = kind; 211 212 if (canonicalPrimaryID == null || canonicalPrimaryID.equalsIgnoreCase("root")) { 213 this.primaryID = ""; 214 this.fallbackID = null; 215 } else { 216 int idx = canonicalPrimaryID.indexOf('@'); 217 if (idx == 4 && canonicalPrimaryID.regionMatches(true, 0, "root", 0, 4)) { 218 this.primaryID = canonicalPrimaryID.substring(4); 219 this.varstart = 0; 220 this.fallbackID = null; 221 } else { 222 this.primaryID = canonicalPrimaryID; 223 this.varstart = idx; 224 225 if (canonicalFallbackID == null || this.primaryID.equals(canonicalFallbackID)) { 226 this.fallbackID = ""; 227 } else { 228 this.fallbackID = canonicalFallbackID; 229 } 230 } 231 } 232 233 this.currentID = varstart == -1 ? this.primaryID : this.primaryID.substring(0, varstart); 234 } 235 236 /** 237 * Return the prefix associated with the kind, or null if the kind is KIND_ANY. 238 */ 239 public String prefix() { 240 return kind == KIND_ANY ? null : Integer.toString(kind()); 241 } 242 243 /** 244 * Return the kind code associated with this key. 245 */ 246 public int kind() { 247 return kind; 248 } 249 250 /** 251 * Return the (canonical) original ID. 252 */ 253 public String canonicalID() { 254 return primaryID; 255 } 256 257 /** 258 * Return the (canonical) current ID, or null if no current id. 259 */ 260 public String currentID() { 261 return currentID; 262 } 263 264 /** 265 * Return the (canonical) current descriptor, or null if no current id. 266 * Includes the keywords, whereas the ID does not include keywords. 267 */ 268 public String currentDescriptor() { 269 String result = currentID(); 270 if (result != null) { 271 StringBuilder buf = new StringBuilder(); // default capacity 16 is usually good enough 272 if (kind != KIND_ANY) { 273 buf.append(prefix()); 274 } 275 buf.append('/'); 276 buf.append(result); 277 if (varstart != -1) { 278 buf.append(primaryID.substring(varstart, primaryID.length())); 279 } 280 result = buf.toString(); 281 } 282 return result; 283 } 284 285 /** 286 * Convenience method to return the locale corresponding to the (canonical) original ID. 287 */ 288 public ULocale canonicalLocale() { 289 return new ULocale(primaryID); 290 } 291 292 /** 293 * Convenience method to return the ulocale corresponding to the (canonical) currentID. 294 */ 295 public ULocale currentLocale() { 296 if (varstart == -1) { 297 return new ULocale(currentID); 298 } else { 299 return new ULocale(currentID + primaryID.substring(varstart)); 300 } 301 } 302 303 /** 304 * If the key has a fallback, modify the key and return true, 305 * otherwise return false.</p> 306 * 307 * <p>First falls back through the primary ID, then through 308 * the fallbackID. The final fallback is "" (root) 309 * unless the primary id was "" (root), in which case 310 * there is no fallback. 311 */ 312 public boolean fallback() { 313 int x = currentID.lastIndexOf('_'); 314 if (x != -1) { 315 while (--x >= 0 && currentID.charAt(x) == '_') { // handle zh__PINYIN 316 } 317 currentID = currentID.substring(0, x+1); 318 return true; 319 } 320 if (fallbackID != null) { 321 currentID = fallbackID; 322 if (fallbackID.length() == 0) { 323 fallbackID = null; 324 } else { 325 fallbackID = ""; 326 } 327 return true; 328 } 329 currentID = null; 330 return false; 331 } 332 333 /** 334 * If a key created from id would eventually fallback to match the 335 * canonical ID of this key, return true. 336 */ 337 public boolean isFallbackOf(String id) { 338 return LocaleUtility.isFallbackOf(canonicalID(), id); 339 } 340 } 341 342 /** 343 * A subclass of Factory that uses LocaleKeys. If 'visible' the 344 * factory reports its IDs. 345 */ 346 public static abstract class LocaleKeyFactory implements Factory { 347 protected final String name; 348 protected final boolean visible; 349 350 public static final boolean VISIBLE = true; 351 public static final boolean INVISIBLE = false; 352 353 /** 354 * Constructor used by subclasses. 355 */ 356 protected LocaleKeyFactory(boolean visible) { 357 this.visible = visible; 358 this.name = null; 359 } 360 361 /** 362 * Constructor used by subclasses. 363 */ 364 protected LocaleKeyFactory(boolean visible, String name) { 365 this.visible = visible; 366 this.name = name; 367 } 368 369 /** 370 * Implement superclass abstract method. This checks the currentID of 371 * the key against the supported IDs, and passes the canonicalLocale and 372 * kind off to handleCreate (which subclasses must implement). 373 */ 374 public Object create(Key key, ICUService service) { 375 if (handlesKey(key)) { 376 LocaleKey lkey = (LocaleKey)key; 377 int kind = lkey.kind(); 378 379 ULocale uloc = lkey.currentLocale(); 380 return handleCreate(uloc, kind, service); 381 } else { 382 // System.out.println("factory: " + this + " did not support id: " + key.currentID()); 383 // System.out.println("supported ids: " + getSupportedIDs()); 384 } 385 return null; 386 } 387 388 protected boolean handlesKey(Key key) { 389 if (key != null) { 390 String id = key.currentID(); 391 Set<String> supported = getSupportedIDs(); 392 return supported.contains(id); 393 } 394 return false; 395 } 396 397 /** 398 * Override of superclass method. 399 */ 400 public void updateVisibleIDs(Map<String, Factory> result) { 401 Set<String> cache = getSupportedIDs(); 402 for (String id : cache) { 403 if (visible) { 404 result.put(id, this); 405 } else { 406 result.remove(id); 407 } 408 } 409 } 410 411 /** 412 * Return a localized name for the locale represented by id. 413 */ 414 public String getDisplayName(String id, ULocale locale) { 415 // assume if the user called this on us, we must have handled some fallback of this id 416 // if (isSupportedID(id)) { 417 if (locale == null) { 418 return id; 419 } 420 ULocale loc = new ULocale(id); 421 return loc.getDisplayName(locale); 422 // } 423 // return null; 424 } 425 426 ///CLOVER:OFF 427 /** 428 * Utility method used by create(Key, ICUService). Subclasses can 429 * implement this instead of create. 430 */ 431 protected Object handleCreate(ULocale loc, int kind, ICUService service) { 432 return null; 433 } 434 ///CLOVER:ON 435 436 /** 437 * Return true if this id is one the factory supports (visible or 438 * otherwise). 439 */ 440 protected boolean isSupportedID(String id) { 441 return getSupportedIDs().contains(id); 442 } 443 444 /** 445 * Return the set of ids that this factory supports (visible or 446 * otherwise). This can be called often and might need to be 447 * cached if it is expensive to create. 448 */ 449 protected Set<String> getSupportedIDs() { 450 return Collections.emptySet(); 451 } 452 453 /** 454 * For debugging. 455 */ 456 public String toString() { 457 StringBuilder buf = new StringBuilder(super.toString()); 458 if (name != null) { 459 buf.append(", name: "); 460 buf.append(name); 461 } 462 buf.append(", visible: "); 463 buf.append(visible); 464 return buf.toString(); 465 } 466 } 467 468 /** 469 * A LocaleKeyFactory that just returns a single object for a kind/locale. 470 */ 471 public static class SimpleLocaleKeyFactory extends LocaleKeyFactory { 472 private final Object obj; 473 private final String id; 474 private final int kind; 475 476 // TODO: remove when we no longer need this 477 public SimpleLocaleKeyFactory(Object obj, ULocale locale, int kind, boolean visible) { 478 this(obj, locale, kind, visible, null); 479 } 480 481 public SimpleLocaleKeyFactory(Object obj, ULocale locale, int kind, boolean visible, String name) { 482 super(visible, name); 483 484 this.obj = obj; 485 this.id = locale.getBaseName(); 486 this.kind = kind; 487 } 488 489 /** 490 * Returns the service object if kind/locale match. Service is not used. 491 */ 492 public Object create(Key key, ICUService service) { 493 if (!(key instanceof LocaleKey)) { 494 return null; 495 } 496 497 LocaleKey lkey = (LocaleKey)key; 498 if (kind != LocaleKey.KIND_ANY && kind != lkey.kind()) { 499 return null; 500 } 501 if (!id.equals(lkey.currentID())) { 502 return null; 503 } 504 505 return obj; 506 } 507 508 protected boolean isSupportedID(String idToCheck) { 509 return this.id.equals(idToCheck); 510 } 511 512 public void updateVisibleIDs(Map<String, Factory> result) { 513 if (visible) { 514 result.put(id, this); 515 } else { 516 result.remove(id); 517 } 518 } 519 520 public String toString() { 521 StringBuilder buf = new StringBuilder(super.toString()); 522 buf.append(", id: "); 523 buf.append(id); 524 buf.append(", kind: "); 525 buf.append(kind); 526 return buf.toString(); 527 } 528 } 529 530 /** 531 * A LocaleKeyFactory that creates a service based on the ICU locale data. 532 * This is a base class for most ICU factories. Subclasses instantiate it 533 * with a constructor that takes a bundle name, which determines the supported 534 * IDs. Subclasses then override handleCreate to create the actual service 535 * object. The default implementation returns a resource bundle. 536 */ 537 public static class ICUResourceBundleFactory extends LocaleKeyFactory { 538 protected final String bundleName; 539 540 /** 541 * Convenience constructor that uses the main ICU bundle name. 542 */ 543 public ICUResourceBundleFactory() { 544 this(ICUResourceBundle.ICU_BASE_NAME); 545 } 546 547 /** 548 * A service factory based on ICU resource data in resources 549 * with the given name. 550 */ 551 public ICUResourceBundleFactory(String bundleName) { 552 super(true); 553 554 this.bundleName = bundleName; 555 } 556 557 /** 558 * Return the supported IDs. This is the set of all locale names for the bundleName. 559 */ 560 protected Set<String> getSupportedIDs() { 561 return ICUResourceBundle.getFullLocaleNameSet(bundleName, loader()); 562 } 563 564 /** 565 * Override of superclass method. 566 */ 567 public void updateVisibleIDs(Map<String, Factory> result) { 568 Set<String> visibleIDs = ICUResourceBundle.getAvailableLocaleNameSet(bundleName, loader()); // only visible ids 569 for (String id : visibleIDs) { 570 result.put(id, this); 571 } 572 } 573 574 /** 575 * Create the service. The default implementation returns the resource bundle 576 * for the locale, ignoring kind, and service. 577 */ 578 protected Object handleCreate(ULocale loc, int kind, ICUService service) { 579 return ICUResourceBundle.getBundleInstance(bundleName, loc, loader()); 580 } 581 582 protected ClassLoader loader() { 583 return ClassLoaderUtil.getClassLoader(getClass()); 584 } 585 586 public String toString() { 587 return super.toString() + ", bundle: " + bundleName; 588 } 589 } 590 591 /** 592 * Return the name of the current fallback locale. If it has changed since this was 593 * last accessed, the service cache is cleared. 594 */ 595 public String validateFallbackLocale() { 596 ULocale loc = ULocale.getDefault(); 597 if (loc != fallbackLocale) { 598 synchronized (this) { 599 if (loc != fallbackLocale) { 600 fallbackLocale = loc; 601 fallbackLocaleName = loc.getBaseName(); 602 clearServiceCache(); 603 } 604 } 605 } 606 return fallbackLocaleName; 607 } 608 609 public Key createKey(String id) { 610 return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale()); 611 } 612 613 public Key createKey(String id, int kind) { 614 return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale(), kind); 615 } 616 617 public Key createKey(ULocale l, int kind) { 618 return LocaleKey.createWithCanonical(l, validateFallbackLocale(), kind); 619 } 620 } 621