• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 com.android.providers.contacts.HanziToPinyin.Token;
20 
21 import android.provider.ContactsContract.FullNameStyle;
22 import android.util.SparseArray;
23 
24 import java.util.ArrayList;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.Locale;
28 
29 /**
30  * This utility class provides customized sort key and name lookup key according the locale.
31  */
32 public class ContactLocaleUtils {
33 
34     /**
35      * This class is the default implementation.
36      * <p>
37      * It should be the base class for other locales' implementation.
38      */
39     public class ContactLocaleUtilsBase {
getSortKey(String displayName)40         public String getSortKey(String displayName) {
41             return displayName;
42         }
43         @SuppressWarnings("unused")
getNameLookupKeys(String name)44         public Iterator<String> getNameLookupKeys(String name) {
45             return null;
46         }
47     }
48 
49     /**
50      * The classes to generate the Chinese style sort and search keys.
51      * <p>
52      * The sorting key is generated as each Chinese character' pinyin proceeding with
53      * space and character itself. If the character's pinyin unable to find, the character
54      * itself will be used.
55      * <p>
56      * The below additional name lookup keys will be generated.
57      * a. Chinese character's pinyin and pinyin's initial character.
58      * b. Latin word and the initial character for Latin word.
59      * The name lookup keys are generated to make sure the name can be found by from any
60      * initial character.
61      */
62     private class ChineseContactUtils extends ContactLocaleUtilsBase {
63         @Override
getSortKey(String displayName)64         public String getSortKey(String displayName) {
65             ArrayList<Token> tokens = HanziToPinyin.getInstance().get(displayName);
66             if (tokens != null && tokens.size() > 0) {
67                 StringBuilder sb = new StringBuilder();
68                 for (Token token : tokens) {
69                     // Put Chinese character's pinyin, then proceed with the
70                     // character itself.
71                     if (Token.PINYIN == token.type) {
72                         if (sb.length() > 0) {
73                             sb.append(' ');
74                         }
75                         sb.append(token.target);
76                         sb.append(' ');
77                         sb.append(token.source);
78                     } else {
79                         if (sb.length() > 0) {
80                             sb.append(' ');
81                         }
82                         sb.append(token.source);
83                     }
84                 }
85                 return sb.toString();
86             }
87             return super.getSortKey(displayName);
88         }
89 
90         @Override
getNameLookupKeys(String name)91         public Iterator<String> getNameLookupKeys(String name) {
92             // TODO : Reduce the object allocation.
93             HashSet<String> keys = new HashSet<String>();
94             ArrayList<Token> tokens = HanziToPinyin.getInstance().get(name);
95             final int tokenCount = tokens.size();
96             final StringBuilder keyPinyin = new StringBuilder();
97             final StringBuilder keyInitial = new StringBuilder();
98             // There is no space among the Chinese Characters, the variant name
99             // lookup key wouldn't work for Chinese. The keyOrignal is used to
100             // build the lookup keys for itself.
101             final StringBuilder keyOrignal = new StringBuilder();
102             for (int i = tokenCount - 1; i >= 0; i--) {
103                 final Token token = tokens.get(i);
104                 if (Token.PINYIN == token.type) {
105                     keyPinyin.insert(0, token.target);
106                     keyInitial.insert(0, token.target.charAt(0));
107                 } else if (Token.LATIN == token.type) {
108                     // Avoid adding space at the end of String.
109                     if (keyPinyin.length() > 0) {
110                         keyPinyin.insert(0, ' ');
111                     }
112                     if (keyOrignal.length() > 0) {
113                         keyOrignal.insert(0, ' ');
114                     }
115                     keyPinyin.insert(0, token.source);
116                     keyInitial.insert(0, token.source.charAt(0));
117                 }
118                 keyOrignal.insert(0, token.source);
119                 keys.add(keyOrignal.toString());
120                 keys.add(keyPinyin.toString());
121                 keys.add(keyInitial.toString());
122             }
123             return keys.iterator();
124         }
125     }
126 
127     private static final String CHINESE_LANGUAGE = Locale.CHINESE.getLanguage().toLowerCase();
128     private static final String JAPANESE_LANGUAGE = Locale.JAPANESE.getLanguage().toLowerCase();
129     private static final String KOREAN_LANGUAGE = Locale.KOREAN.getLanguage().toLowerCase();
130 
131     private static ContactLocaleUtils sSingleton;
132     private final SparseArray<ContactLocaleUtilsBase> mUtils =
133             new SparseArray<ContactLocaleUtilsBase>();
134 
135     private final ContactLocaleUtilsBase mBase = new ContactLocaleUtilsBase();
136 
137     private String mLanguage;
138 
ContactLocaleUtils()139     private ContactLocaleUtils() {
140         setLocale(null);
141     }
142 
setLocale(Locale currentLocale)143     public void setLocale(Locale currentLocale) {
144         if (currentLocale == null) {
145             mLanguage = Locale.getDefault().getLanguage().toLowerCase();
146         } else {
147             mLanguage = currentLocale.getLanguage().toLowerCase();
148         }
149     }
150 
getSortKey(String displayName, int nameStyle)151     public String getSortKey(String displayName, int nameStyle) {
152         return getForSort(Integer.valueOf(nameStyle)).getSortKey(displayName);
153     }
154 
getNameLookupKeys(String name, int nameStyle)155     public Iterator<String> getNameLookupKeys(String name, int nameStyle) {
156         return getForNameLookup(Integer.valueOf(nameStyle)).getNameLookupKeys(name);
157     }
158 
159     /**
160      *  Determine which utility should be used for generating NameLookupKey.
161      *  <p>
162      *  a. For Western style name, if the current language is Chinese, the
163      *     ChineseContactUtils should be used.
164      *  b. For Chinese and CJK style name if current language is neither Japanese or Korean,
165      *     the ChineseContactUtils should be used.
166      */
getForNameLookup(Integer nameStyle)167     private ContactLocaleUtilsBase getForNameLookup(Integer nameStyle) {
168         int nameStyleInt = nameStyle.intValue();
169         Integer adjustedUtil = Integer.valueOf(getAdjustedStyle(nameStyleInt));
170         if (CHINESE_LANGUAGE.equals(mLanguage) && nameStyleInt == FullNameStyle.WESTERN) {
171             adjustedUtil = Integer.valueOf(FullNameStyle.CHINESE);
172         }
173         return get(adjustedUtil);
174     }
175 
get(Integer nameStyle)176     private synchronized ContactLocaleUtilsBase get(Integer nameStyle) {
177         ContactLocaleUtilsBase utils = mUtils.get(nameStyle);
178         if (utils == null) {
179             if (nameStyle.intValue() == FullNameStyle.CHINESE) {
180                 utils = new ChineseContactUtils();
181                 mUtils.put(nameStyle, utils);
182             }
183         }
184         return (utils == null) ? mBase : utils;
185     }
186 
187     /**
188      *  Determine the which utility should be used for generating sort key.
189      *  <p>
190      *  For Chinese and CJK style name if current language is neither Japanese or Korean,
191      *  the ChineseContactUtils should be used.
192      */
getForSort(Integer nameStyle)193     private ContactLocaleUtilsBase getForSort(Integer nameStyle) {
194         return get(Integer.valueOf(getAdjustedStyle(nameStyle.intValue())));
195     }
196 
getIntance()197     public static synchronized ContactLocaleUtils getIntance() {
198         if (sSingleton == null) {
199             sSingleton = new ContactLocaleUtils();
200         }
201         return sSingleton;
202     }
203 
getAdjustedStyle(int nameStyle)204     private int getAdjustedStyle(int nameStyle) {
205         if (nameStyle == FullNameStyle.CJK  && !JAPANESE_LANGUAGE.equals(mLanguage) &&
206                 !KOREAN_LANGUAGE.equals(mLanguage)) {
207             return FullNameStyle.CHINESE;
208         } else {
209             return nameStyle;
210         }
211     }
212 }
213