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