Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2012 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.inputmethod.latin.utils;
     18 
     19 import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE;
     20 import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE;
     21 import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
     22 import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME;
     23 
     24 import android.os.Build;
     25 import android.text.TextUtils;
     26 import android.view.inputmethod.InputMethodSubtype;
     27 
     28 import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
     29 import com.android.inputmethod.latin.Constants;
     30 import com.android.inputmethod.latin.R;
     31 
     32 import java.util.ArrayList;
     33 
     34 public final class AdditionalSubtypeUtils {
     35     private static final InputMethodSubtype[] EMPTY_SUBTYPE_ARRAY = new InputMethodSubtype[0];
     36 
     37     private AdditionalSubtypeUtils() {
     38         // This utility class is not publicly instantiable.
     39     }
     40 
     41     public static boolean isAdditionalSubtype(final InputMethodSubtype subtype) {
     42         return subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE);
     43     }
     44 
     45     private static final String LOCALE_AND_LAYOUT_SEPARATOR = ":";
     46     private static final String PREF_SUBTYPE_SEPARATOR = ";";
     47 
     48     public static InputMethodSubtype createAdditionalSubtype(final String localeString,
     49             final String keyboardLayoutSetName, final String extraValue) {
     50         final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName;
     51         final String layoutDisplayNameExtraValue;
     52         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
     53                 && SubtypeLocaleUtils.isExceptionalLocale(localeString)) {
     54             final String layoutDisplayName = SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(
     55                     keyboardLayoutSetName);
     56             layoutDisplayNameExtraValue = StringUtils.appendToCommaSplittableTextIfNotExists(
     57                     UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME + "=" + layoutDisplayName, extraValue);
     58         } else {
     59             layoutDisplayNameExtraValue = extraValue;
     60         }
     61         final String additionalSubtypeExtraValue =
     62                 StringUtils.appendToCommaSplittableTextIfNotExists(
     63                         IS_ADDITIONAL_SUBTYPE, layoutDisplayNameExtraValue);
     64         final int nameId = SubtypeLocaleUtils.getSubtypeNameId(localeString, keyboardLayoutSetName);
     65         return buildInputMethodSubtype(
     66                 nameId, localeString, layoutExtraValue, additionalSubtypeExtraValue);
     67     }
     68 
     69     public static String getPrefSubtype(final InputMethodSubtype subtype) {
     70         final String localeString = subtype.getLocale();
     71         final String keyboardLayoutSetName = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype);
     72         final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName;
     73         final String extraValue = StringUtils.removeFromCommaSplittableTextIfExists(
     74                 layoutExtraValue, StringUtils.removeFromCommaSplittableTextIfExists(
     75                         IS_ADDITIONAL_SUBTYPE, subtype.getExtraValue()));
     76         final String basePrefSubtype = localeString + LOCALE_AND_LAYOUT_SEPARATOR
     77                 + keyboardLayoutSetName;
     78         return extraValue.isEmpty() ? basePrefSubtype
     79                 : basePrefSubtype + LOCALE_AND_LAYOUT_SEPARATOR + extraValue;
     80     }
     81 
     82     public static InputMethodSubtype createAdditionalSubtype(final String prefSubtype) {
     83         final String elems[] = prefSubtype.split(LOCALE_AND_LAYOUT_SEPARATOR);
     84         if (elems.length < 2 || elems.length > 3) {
     85             throw new RuntimeException("Unknown additional subtype specified: " + prefSubtype);
     86         }
     87         final String localeString = elems[0];
     88         final String keyboardLayoutSetName = elems[1];
     89         final String extraValue = (elems.length == 3) ? elems[2] : null;
     90         return createAdditionalSubtype(localeString, keyboardLayoutSetName, extraValue);
     91     }
     92 
     93     public static InputMethodSubtype[] createAdditionalSubtypesArray(final String prefSubtypes) {
     94         if (TextUtils.isEmpty(prefSubtypes)) {
     95             return EMPTY_SUBTYPE_ARRAY;
     96         }
     97         final String[] prefSubtypeArray = prefSubtypes.split(PREF_SUBTYPE_SEPARATOR);
     98         final ArrayList<InputMethodSubtype> subtypesList =
     99                 CollectionUtils.newArrayList(prefSubtypeArray.length);
    100         for (final String prefSubtype : prefSubtypeArray) {
    101             final InputMethodSubtype subtype = createAdditionalSubtype(prefSubtype);
    102             if (subtype.getNameResId() == SubtypeLocaleUtils.UNKNOWN_KEYBOARD_LAYOUT) {
    103                 // Skip unknown keyboard layout subtype. This may happen when predefined keyboard
    104                 // layout has been removed.
    105                 continue;
    106             }
    107             subtypesList.add(subtype);
    108         }
    109         return subtypesList.toArray(new InputMethodSubtype[subtypesList.size()]);
    110     }
    111 
    112     public static String createPrefSubtypes(final InputMethodSubtype[] subtypes) {
    113         if (subtypes == null || subtypes.length == 0) {
    114             return "";
    115         }
    116         final StringBuilder sb = new StringBuilder();
    117         for (final InputMethodSubtype subtype : subtypes) {
    118             if (sb.length() > 0) {
    119                 sb.append(PREF_SUBTYPE_SEPARATOR);
    120             }
    121             sb.append(getPrefSubtype(subtype));
    122         }
    123         return sb.toString();
    124     }
    125 
    126     public static String createPrefSubtypes(final String[] prefSubtypes) {
    127         if (prefSubtypes == null || prefSubtypes.length == 0) {
    128             return "";
    129         }
    130         final StringBuilder sb = new StringBuilder();
    131         for (final String prefSubtype : prefSubtypes) {
    132             if (sb.length() > 0) {
    133                 sb.append(PREF_SUBTYPE_SEPARATOR);
    134             }
    135             sb.append(prefSubtype);
    136         }
    137         return sb.toString();
    138     }
    139 
    140     private static InputMethodSubtype buildInputMethodSubtype(int nameId, String localeString,
    141             String layoutExtraValue, String additionalSubtypeExtraValue) {
    142         // CAVEAT! If you want to change subtypeId after changing the extra values,
    143         // you must change "getInputMethodSubtypeId". But it will remove the additional keyboard
    144         // from the current users. So, you should be really careful to change it.
    145         final int subtypeId = getInputMethodSubtypeId(nameId, localeString, layoutExtraValue,
    146                 additionalSubtypeExtraValue);
    147         final String extraValue;
    148         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    149             extraValue = layoutExtraValue + "," + additionalSubtypeExtraValue
    150                     + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE
    151                     + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
    152         } else {
    153             extraValue = layoutExtraValue + "," + additionalSubtypeExtraValue;
    154         }
    155         return InputMethodSubtypeCompatUtils.newInputMethodSubtype(nameId,
    156                 R.drawable.ic_ime_switcher_dark, localeString, KEYBOARD_MODE, extraValue,
    157                 false, false, subtypeId);
    158     }
    159 
    160     private static int getInputMethodSubtypeId(int nameId, String localeString,
    161             String layoutExtraValue, String additionalSubtypeExtraValue) {
    162         // TODO: Use InputMethodSubtypeBuilder once we use SDK version 19.
    163         return (new InputMethodSubtype(nameId, R.drawable.ic_ime_switcher_dark,
    164                 localeString, KEYBOARD_MODE, layoutExtraValue + "," + additionalSubtypeExtraValue,
    165                         false, false)).hashCode();
    166     }
    167 }
    168