Home | History | Annotate | Download | only in impl
      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