1 /*
2  * Copyright (C) 2014 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 com.android.providers.contacts;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.icu.util.ULocale;
22 import android.os.LocaleList;
23 import android.text.TextUtils;
24 
25 import com.google.common.annotations.VisibleForTesting;
26 import java.util.Locale;
27 
28 public class LocaleSet {
29     private static final String SCRIPT_SIMPLIFIED_CHINESE = "Hans";
30     private static final String SCRIPT_TRADITIONAL_CHINESE = "Hant";
31 
32     private final Locale mDefaultLocaleOverrideForTest;
33     private final LocaleList mLocaleList;
34 
LocaleSet(LocaleList localeList, Locale defaultLocaleOverrideForTest)35     private LocaleSet(LocaleList localeList, Locale defaultLocaleOverrideForTest) {
36         mLocaleList = localeList;
37         mDefaultLocaleOverrideForTest = defaultLocaleOverrideForTest;
38     }
39 
newDefault()40     public static LocaleSet newDefault() {
41         return new LocaleSet(LocaleList.getDefault(),
42                 /*defaultLocaleOverrideForTest= */ null);
43     }
44 
45     @VisibleForTesting
newForTest(Locale... locales)46     public static LocaleSet newForTest(Locale... locales) {
47         return new LocaleSet(new LocaleList(locales), locales[0]);
48     }
49 
50     @VisibleForTesting
isLanguageChinese(@ullable Locale locale)51     static boolean isLanguageChinese(@Nullable Locale locale) {
52         return locale != null && "zh".equals(locale.getLanguage());
53     }
54 
55     @VisibleForTesting
isLanguageJapanese(@ullable Locale locale)56     static boolean isLanguageJapanese(@Nullable Locale locale) {
57         return locale != null && "ja".equals(locale.getLanguage());
58     }
59 
60     @VisibleForTesting
isLanguageKorean(@ullable Locale locale)61     static boolean isLanguageKorean(@Nullable Locale locale) {
62         return locale != null && "ko".equals(locale.getLanguage());
63     }
64 
65     @VisibleForTesting
isLocaleCJK(@ullable Locale locale)66     static boolean isLocaleCJK(@Nullable Locale locale) {
67         return isLanguageChinese(locale) ||
68                 isLanguageJapanese(locale) ||
69                 isLanguageKorean(locale);
70     }
71 
getLikelyScript(Locale locale)72     private static String getLikelyScript(Locale locale) {
73         final String script = locale.getScript();
74         if (!script.isEmpty()) {
75             return script;
76         } else {
77             return ULocale.addLikelySubtags(ULocale.forLocale(locale)).getScript();
78         }
79     }
80 
81     /**
82      * @return the script if the language is Chinese, and otherwise null.
83      */
84     @VisibleForTesting
getScriptIfChinese(@ullable Locale locale)85     static String getScriptIfChinese(@Nullable Locale locale) {
86         return isLanguageChinese(locale) ? getLikelyScript(locale) : null;
87     }
88 
isLocaleSimplifiedChinese(@ullable Locale locale)89     static boolean isLocaleSimplifiedChinese(@Nullable Locale locale) {
90         return SCRIPT_SIMPLIFIED_CHINESE.equals(getScriptIfChinese(locale));
91     }
92 
93     @VisibleForTesting
isLocaleTraditionalChinese(@ullable Locale locale)94     static boolean isLocaleTraditionalChinese(@Nullable Locale locale) {
95         return SCRIPT_TRADITIONAL_CHINESE.equals(getScriptIfChinese(locale));
96     }
97 
98     /**
99      * Returns the primary locale, which may not be the first item of {@link #getAllLocales}.
100      * (See {@link LocaleList})
101      */
getPrimaryLocale()102     public @NonNull Locale getPrimaryLocale() {
103         if (mDefaultLocaleOverrideForTest != null) {
104             return mDefaultLocaleOverrideForTest;
105         }
106         return Locale.getDefault();
107     }
108 
getAllLocales()109     public @NonNull LocaleList getAllLocales() {
110         return mLocaleList;
111     }
112 
isPrimaryLocaleCJK()113     public boolean isPrimaryLocaleCJK() {
114         return isLocaleCJK(getPrimaryLocale());
115     }
116 
117     /**
118      * @return true if Japanese is found in the list before simplified Chinese.
119      */
shouldPreferJapanese()120     public boolean shouldPreferJapanese() {
121         if (isLanguageJapanese(getPrimaryLocale())) {
122             return true;
123         }
124         for (int i = 0; i < mLocaleList.size(); i++) {
125             final Locale l = mLocaleList.get(i);
126             if (isLanguageJapanese(l)) {
127                 return true;
128             }
129             if (isLocaleSimplifiedChinese(l)) {
130                 return false;
131             }
132         }
133         return false;
134     }
135 
136     /**
137      * @return true if simplified Chinese is found before Japanese or traditional Chinese.
138      */
shouldPreferSimplifiedChinese()139     public boolean shouldPreferSimplifiedChinese() {
140         if (isLocaleSimplifiedChinese(getPrimaryLocale())) {
141             return true;
142         }
143         for (int i = 0; i < mLocaleList.size(); i++) {
144             final Locale l = mLocaleList.get(i);
145             if (isLocaleSimplifiedChinese(l)) {
146                 return true;
147             }
148             if (isLanguageJapanese(l)) {
149                 return false;
150             }
151             if (isLocaleTraditionalChinese(l)) { // Traditional chinese wins here.
152                 return false;
153             }
154         }
155         return false;
156     }
157 
158     @Override
equals(Object object)159     public boolean equals(Object object) {
160         if (object == this) {
161             return true;
162         }
163         if (object instanceof LocaleSet) {
164             final LocaleSet other = (LocaleSet) object;
165             return mLocaleList.equals(other.mLocaleList);
166         }
167         return false;
168     }
169 
170     @Override
toString()171     public final String toString() {
172         return mLocaleList.toString();
173     }
174 }
175