Home | History | Annotate | Download | only in keyboard
      1 /*
      2  * Copyright (C) 2015 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.keyboard;
     18 
     19 import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
     20 
     21 import android.text.InputType;
     22 import android.text.TextUtils;
     23 import android.view.inputmethod.EditorInfo;
     24 
     25 import com.android.inputmethod.compat.EditorInfoCompatUtils;
     26 import com.android.inputmethod.latin.RichInputMethodSubtype;
     27 import com.android.inputmethod.latin.utils.InputTypeUtils;
     28 
     29 import java.util.Arrays;
     30 import java.util.Locale;
     31 
     32 /**
     33  * Unique identifier for each keyboard type.
     34  */
     35 public final class KeyboardId {
     36     public static final int MODE_TEXT = 0;
     37     public static final int MODE_URL = 1;
     38     public static final int MODE_EMAIL = 2;
     39     public static final int MODE_IM = 3;
     40     public static final int MODE_PHONE = 4;
     41     public static final int MODE_NUMBER = 5;
     42     public static final int MODE_DATE = 6;
     43     public static final int MODE_TIME = 7;
     44     public static final int MODE_DATETIME = 8;
     45 
     46     public static final int ELEMENT_ALPHABET = 0;
     47     public static final int ELEMENT_ALPHABET_MANUAL_SHIFTED = 1;
     48     public static final int ELEMENT_ALPHABET_AUTOMATIC_SHIFTED = 2;
     49     public static final int ELEMENT_ALPHABET_SHIFT_LOCKED = 3;
     50     public static final int ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED = 4;
     51     public static final int ELEMENT_SYMBOLS = 5;
     52     public static final int ELEMENT_SYMBOLS_SHIFTED = 6;
     53     public static final int ELEMENT_PHONE = 7;
     54     public static final int ELEMENT_PHONE_SYMBOLS = 8;
     55     public static final int ELEMENT_NUMBER = 9;
     56     public static final int ELEMENT_EMOJI_RECENTS = 10;
     57     public static final int ELEMENT_EMOJI_CATEGORY1 = 11;
     58     public static final int ELEMENT_EMOJI_CATEGORY2 = 12;
     59     public static final int ELEMENT_EMOJI_CATEGORY3 = 13;
     60     public static final int ELEMENT_EMOJI_CATEGORY4 = 14;
     61     public static final int ELEMENT_EMOJI_CATEGORY5 = 15;
     62     public static final int ELEMENT_EMOJI_CATEGORY6 = 16;
     63     public static final int ELEMENT_EMOJI_CATEGORY7 = 17;
     64     public static final int ELEMENT_EMOJI_CATEGORY8 = 18;
     65     public static final int ELEMENT_EMOJI_CATEGORY9 = 19;
     66     public static final int ELEMENT_EMOJI_CATEGORY10 = 20;
     67     public static final int ELEMENT_EMOJI_CATEGORY11 = 21;
     68     public static final int ELEMENT_EMOJI_CATEGORY12 = 22;
     69     public static final int ELEMENT_EMOJI_CATEGORY13 = 23;
     70     public static final int ELEMENT_EMOJI_CATEGORY14 = 24;
     71     public static final int ELEMENT_EMOJI_CATEGORY15 = 25;
     72     public static final int ELEMENT_EMOJI_CATEGORY16 = 26;
     73 
     74     public final RichInputMethodSubtype mSubtype;
     75     public final int mWidth;
     76     public final int mHeight;
     77     public final int mMode;
     78     public final int mElementId;
     79     public final EditorInfo mEditorInfo;
     80     public final boolean mClobberSettingsKey;
     81     public final boolean mLanguageSwitchKeyEnabled;
     82     public final String mCustomActionLabel;
     83     public final boolean mHasShortcutKey;
     84     public final boolean mIsSplitLayout;
     85 
     86     private final int mHashCode;
     87 
     88     public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) {
     89         mSubtype = params.mSubtype;
     90         mWidth = params.mKeyboardWidth;
     91         mHeight = params.mKeyboardHeight;
     92         mMode = params.mMode;
     93         mElementId = elementId;
     94         mEditorInfo = params.mEditorInfo;
     95         mClobberSettingsKey = params.mNoSettingsKey;
     96         mLanguageSwitchKeyEnabled = params.mLanguageSwitchKeyEnabled;
     97         mCustomActionLabel = (mEditorInfo.actionLabel != null)
     98                 ? mEditorInfo.actionLabel.toString() : null;
     99         mHasShortcutKey = params.mVoiceInputKeyEnabled;
    100         mIsSplitLayout = params.mIsSplitLayoutEnabled;
    101 
    102         mHashCode = computeHashCode(this);
    103     }
    104 
    105     private static int computeHashCode(final KeyboardId id) {
    106         return Arrays.hashCode(new Object[] {
    107                 id.mElementId,
    108                 id.mMode,
    109                 id.mWidth,
    110                 id.mHeight,
    111                 id.passwordInput(),
    112                 id.mClobberSettingsKey,
    113                 id.mHasShortcutKey,
    114                 id.mLanguageSwitchKeyEnabled,
    115                 id.isMultiLine(),
    116                 id.imeAction(),
    117                 id.mCustomActionLabel,
    118                 id.navigateNext(),
    119                 id.navigatePrevious(),
    120                 id.mSubtype,
    121                 id.mIsSplitLayout
    122         });
    123     }
    124 
    125     private boolean equals(final KeyboardId other) {
    126         if (other == this)
    127             return true;
    128         return other.mElementId == mElementId
    129                 && other.mMode == mMode
    130                 && other.mWidth == mWidth
    131                 && other.mHeight == mHeight
    132                 && other.passwordInput() == passwordInput()
    133                 && other.mClobberSettingsKey == mClobberSettingsKey
    134                 && other.mHasShortcutKey == mHasShortcutKey
    135                 && other.mLanguageSwitchKeyEnabled == mLanguageSwitchKeyEnabled
    136                 && other.isMultiLine() == isMultiLine()
    137                 && other.imeAction() == imeAction()
    138                 && TextUtils.equals(other.mCustomActionLabel, mCustomActionLabel)
    139                 && other.navigateNext() == navigateNext()
    140                 && other.navigatePrevious() == navigatePrevious()
    141                 && other.mSubtype.equals(mSubtype)
    142                 && other.mIsSplitLayout == mIsSplitLayout;
    143     }
    144 
    145     private static boolean isAlphabetKeyboard(final int elementId) {
    146         return elementId < ELEMENT_SYMBOLS;
    147     }
    148 
    149     public boolean isAlphabetKeyboard() {
    150         return isAlphabetKeyboard(mElementId);
    151     }
    152 
    153     public boolean navigateNext() {
    154         return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0
    155                 || imeAction() == EditorInfo.IME_ACTION_NEXT;
    156     }
    157 
    158     public boolean navigatePrevious() {
    159         return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0
    160                 || imeAction() == EditorInfo.IME_ACTION_PREVIOUS;
    161     }
    162 
    163     public boolean passwordInput() {
    164         final int inputType = mEditorInfo.inputType;
    165         return InputTypeUtils.isPasswordInputType(inputType)
    166                 || InputTypeUtils.isVisiblePasswordInputType(inputType);
    167     }
    168 
    169     public boolean isMultiLine() {
    170         return (mEditorInfo.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0;
    171     }
    172 
    173     public int imeAction() {
    174         return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo);
    175     }
    176 
    177     public Locale getLocale() {
    178         return mSubtype.getLocale();
    179     }
    180 
    181     @Override
    182     public boolean equals(final Object other) {
    183         return other instanceof KeyboardId && equals((KeyboardId) other);
    184     }
    185 
    186     @Override
    187     public int hashCode() {
    188         return mHashCode;
    189     }
    190 
    191     @Override
    192     public String toString() {
    193         return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s]",
    194                 elementIdToName(mElementId),
    195                 mSubtype.getLocale(),
    196                 mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
    197                 mWidth, mHeight,
    198                 modeName(mMode),
    199                 actionName(imeAction()),
    200                 (navigateNext() ? " navigateNext" : ""),
    201                 (navigatePrevious() ? " navigatePrevious" : ""),
    202                 (mClobberSettingsKey ? " clobberSettingsKey" : ""),
    203                 (passwordInput() ? " passwordInput" : ""),
    204                 (mHasShortcutKey ? " hasShortcutKey" : ""),
    205                 (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""),
    206                 (isMultiLine() ? " isMultiLine" : ""),
    207                 (mIsSplitLayout ? " isSplitLayout" : "")
    208         );
    209     }
    210 
    211     public static boolean equivalentEditorInfoForKeyboard(final EditorInfo a, final EditorInfo b) {
    212         if (a == null && b == null) return true;
    213         if (a == null || b == null) return false;
    214         return a.inputType == b.inputType
    215                 && a.imeOptions == b.imeOptions
    216                 && TextUtils.equals(a.privateImeOptions, b.privateImeOptions);
    217     }
    218 
    219     public static String elementIdToName(final int elementId) {
    220         switch (elementId) {
    221         case ELEMENT_ALPHABET: return "alphabet";
    222         case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted";
    223         case ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: return "alphabetAutomaticShifted";
    224         case ELEMENT_ALPHABET_SHIFT_LOCKED: return "alphabetShiftLocked";
    225         case ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: return "alphabetShiftLockShifted";
    226         case ELEMENT_SYMBOLS: return "symbols";
    227         case ELEMENT_SYMBOLS_SHIFTED: return "symbolsShifted";
    228         case ELEMENT_PHONE: return "phone";
    229         case ELEMENT_PHONE_SYMBOLS: return "phoneSymbols";
    230         case ELEMENT_NUMBER: return "number";
    231         case ELEMENT_EMOJI_RECENTS: return "emojiRecents";
    232         case ELEMENT_EMOJI_CATEGORY1: return "emojiCategory1";
    233         case ELEMENT_EMOJI_CATEGORY2: return "emojiCategory2";
    234         case ELEMENT_EMOJI_CATEGORY3: return "emojiCategory3";
    235         case ELEMENT_EMOJI_CATEGORY4: return "emojiCategory4";
    236         case ELEMENT_EMOJI_CATEGORY5: return "emojiCategory5";
    237         case ELEMENT_EMOJI_CATEGORY6: return "emojiCategory6";
    238         case ELEMENT_EMOJI_CATEGORY7: return "emojiCategory7";
    239         case ELEMENT_EMOJI_CATEGORY8: return "emojiCategory8";
    240         case ELEMENT_EMOJI_CATEGORY9: return "emojiCategory9";
    241         case ELEMENT_EMOJI_CATEGORY10: return "emojiCategory10";
    242         case ELEMENT_EMOJI_CATEGORY11: return "emojiCategory11";
    243         case ELEMENT_EMOJI_CATEGORY12: return "emojiCategory12";
    244         case ELEMENT_EMOJI_CATEGORY13: return "emojiCategory13";
    245         case ELEMENT_EMOJI_CATEGORY14: return "emojiCategory14";
    246         case ELEMENT_EMOJI_CATEGORY15: return "emojiCategory15";
    247         case ELEMENT_EMOJI_CATEGORY16: return "emojiCategory16";
    248         default: return null;
    249         }
    250     }
    251 
    252     public static String modeName(final int mode) {
    253         switch (mode) {
    254         case MODE_TEXT: return "text";
    255         case MODE_URL: return "url";
    256         case MODE_EMAIL: return "email";
    257         case MODE_IM: return "im";
    258         case MODE_PHONE: return "phone";
    259         case MODE_NUMBER: return "number";
    260         case MODE_DATE: return "date";
    261         case MODE_TIME: return "time";
    262         case MODE_DATETIME: return "datetime";
    263         default: return null;
    264         }
    265     }
    266 
    267     public static String actionName(final int actionId) {
    268         return (actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel"
    269                 : EditorInfoCompatUtils.imeActionName(actionId);
    270     }
    271 }
    272