1 package com.android.launcher3.compat;
2 
3 import android.content.Context;
4 import android.icu.text.AlphabeticIndex;
5 import android.os.LocaleList;
6 
7 import com.android.launcher3.Utilities;
8 
9 import java.util.Locale;
10 
11 import androidx.annotation.NonNull;
12 
13 public class AlphabeticIndexCompat {
14 
15     private static final String MID_DOT = "\u2219";
16     private final String mDefaultMiscLabel;
17 
18     private final AlphabeticIndex.ImmutableIndex mBaseIndex;
19 
AlphabeticIndexCompat(Context context)20     public AlphabeticIndexCompat(Context context) {
21         this(context.getResources().getConfiguration().getLocales());
22     }
23 
AlphabeticIndexCompat(LocaleList locales)24     public AlphabeticIndexCompat(LocaleList locales) {
25         int localeCount = locales.size();
26 
27         Locale primaryLocale = localeCount == 0 ? Locale.ENGLISH : locales.get(0);
28         AlphabeticIndex indexBuilder = new AlphabeticIndex(primaryLocale);
29         for (int i = 1; i < localeCount; i++) {
30             indexBuilder.addLabels(locales.get(i));
31         }
32         indexBuilder.addLabels(Locale.ENGLISH);
33         mBaseIndex = indexBuilder.buildImmutableIndex();
34 
35         if (primaryLocale.getLanguage().equals(Locale.JAPANESE.getLanguage())) {
36             // Japanese character 他 ("misc")
37             mDefaultMiscLabel = "\u4ed6";
38             // TODO(winsonc, omakoto): We need to handle Japanese sections better,
39             // especially the kanji
40         } else {
41             // Dot
42             mDefaultMiscLabel = MID_DOT;
43         }
44     }
45 
46     /**
47      * Computes the section name for an given string {@param s}.
48      */
computeSectionName(@onNull CharSequence cs)49     public String computeSectionName(@NonNull CharSequence cs) {
50         String s = Utilities.trim(cs);
51         String sectionName = mBaseIndex.getBucket(mBaseIndex.getBucketIndex(s)).getLabel();
52         if (Utilities.trim(sectionName).isEmpty() && s.length() > 0) {
53             int c = s.codePointAt(0);
54             boolean startsWithDigit = Character.isDigit(c);
55             if (startsWithDigit) {
56                 // Digit section
57                 return "#";
58             } else {
59                 boolean startsWithLetter = Character.isLetter(c);
60                 if (startsWithLetter) {
61                     return mDefaultMiscLabel;
62                 } else {
63                     // In languages where these differ, this ensures that we differentiate
64                     // between the misc section in the native language and a misc section
65                     // for everything else.
66                     return MID_DOT;
67                 }
68             }
69         }
70         return sectionName;
71     }
72 }
73