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