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.inputmethod.keyboard; 18 19 import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; 20 21 import android.text.InputType; 22 import android.text.TextUtils; 23 import android.view.inputmethod.EditorInfo; 24 import android.view.inputmethod.InputMethodSubtype; 25 26 import com.android.inputmethod.compat.EditorInfoCompatUtils; 27 import com.android.inputmethod.latin.utils.InputTypeUtils; 28 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; 29 30 import java.util.Arrays; 31 import java.util.Locale; 32 33 /** 34 * Unique identifier for each keyboard type. 35 */ 36 public final class KeyboardId { 37 public static final int MODE_TEXT = 0; 38 public static final int MODE_URL = 1; 39 public static final int MODE_EMAIL = 2; 40 public static final int MODE_IM = 3; 41 public static final int MODE_PHONE = 4; 42 public static final int MODE_NUMBER = 5; 43 public static final int MODE_DATE = 6; 44 public static final int MODE_TIME = 7; 45 public static final int MODE_DATETIME = 8; 46 47 public static final int ELEMENT_ALPHABET = 0; 48 public static final int ELEMENT_ALPHABET_MANUAL_SHIFTED = 1; 49 public static final int ELEMENT_ALPHABET_AUTOMATIC_SHIFTED = 2; 50 public static final int ELEMENT_ALPHABET_SHIFT_LOCKED = 3; 51 public static final int ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED = 4; 52 public static final int ELEMENT_SYMBOLS = 5; 53 public static final int ELEMENT_SYMBOLS_SHIFTED = 6; 54 public static final int ELEMENT_PHONE = 7; 55 public static final int ELEMENT_PHONE_SYMBOLS = 8; 56 public static final int ELEMENT_NUMBER = 9; 57 public static final int ELEMENT_EMOJI_RECENTS = 10; 58 public static final int ELEMENT_EMOJI_CATEGORY1 = 11; 59 public static final int ELEMENT_EMOJI_CATEGORY2 = 12; 60 public static final int ELEMENT_EMOJI_CATEGORY3 = 13; 61 public static final int ELEMENT_EMOJI_CATEGORY4 = 14; 62 public static final int ELEMENT_EMOJI_CATEGORY5 = 15; 63 public static final int ELEMENT_EMOJI_CATEGORY6 = 16; 64 65 public final InputMethodSubtype mSubtype; 66 public final Locale mLocale; 67 public final int mWidth; 68 public final int mHeight; 69 public final int mMode; 70 public final int mElementId; 71 private final EditorInfo mEditorInfo; 72 public final boolean mClobberSettingsKey; 73 public final boolean mShortcutKeyEnabled; 74 public final boolean mShortcutKeyOnSymbols; 75 public final boolean mLanguageSwitchKeyEnabled; 76 public final String mCustomActionLabel; 77 public final boolean mHasShortcutKey; 78 79 private final int mHashCode; 80 81 public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) { 82 mSubtype = params.mSubtype; 83 mLocale = SubtypeLocaleUtils.getSubtypeLocale(mSubtype); 84 mWidth = params.mKeyboardWidth; 85 mHeight = params.mKeyboardHeight; 86 mMode = params.mMode; 87 mElementId = elementId; 88 mEditorInfo = params.mEditorInfo; 89 mClobberSettingsKey = params.mNoSettingsKey; 90 mShortcutKeyEnabled = params.mVoiceKeyEnabled; 91 mShortcutKeyOnSymbols = mShortcutKeyEnabled && !params.mVoiceKeyOnMain; 92 mLanguageSwitchKeyEnabled = params.mLanguageSwitchKeyEnabled; 93 mCustomActionLabel = (mEditorInfo.actionLabel != null) 94 ? mEditorInfo.actionLabel.toString() : null; 95 final boolean alphabetMayHaveShortcutKey = isAlphabetKeyboard(elementId) 96 && !mShortcutKeyOnSymbols; 97 final boolean symbolsMayHaveShortcutKey = (elementId == KeyboardId.ELEMENT_SYMBOLS) 98 && mShortcutKeyOnSymbols; 99 mHasShortcutKey = mShortcutKeyEnabled 100 && (alphabetMayHaveShortcutKey || symbolsMayHaveShortcutKey); 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.mShortcutKeyEnabled, 114 id.mShortcutKeyOnSymbols, 115 id.mLanguageSwitchKeyEnabled, 116 id.isMultiLine(), 117 id.imeAction(), 118 id.mCustomActionLabel, 119 id.navigateNext(), 120 id.navigatePrevious(), 121 id.mSubtype 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.mShortcutKeyEnabled == mShortcutKeyEnabled 135 && other.mShortcutKeyOnSymbols == mShortcutKeyOnSymbols 136 && other.mLanguageSwitchKeyEnabled == mLanguageSwitchKeyEnabled 137 && other.isMultiLine() == isMultiLine() 138 && other.imeAction() == imeAction() 139 && TextUtils.equals(other.mCustomActionLabel, mCustomActionLabel) 140 && other.navigateNext() == navigateNext() 141 && other.navigatePrevious() == navigatePrevious() 142 && other.mSubtype.equals(mSubtype); 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 @Override 178 public boolean equals(final Object other) { 179 return other instanceof KeyboardId && equals((KeyboardId) other); 180 } 181 182 @Override 183 public int hashCode() { 184 return mHashCode; 185 } 186 187 @Override 188 public String toString() { 189 return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s %s%s%s%s%s%s%s%s%s]", 190 elementIdToName(mElementId), 191 mLocale, mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), 192 mWidth, mHeight, 193 modeName(mMode), 194 imeAction(), 195 (navigateNext() ? "navigateNext" : ""), 196 (navigatePrevious() ? "navigatePrevious" : ""), 197 (mClobberSettingsKey ? " clobberSettingsKey" : ""), 198 (passwordInput() ? " passwordInput" : ""), 199 (mShortcutKeyEnabled ? " shortcutKeyEnabled" : ""), 200 (mShortcutKeyOnSymbols ? " shortcutKeyOnSymbols" : ""), 201 (mHasShortcutKey ? " hasShortcutKey" : ""), 202 (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""), 203 (isMultiLine() ? "isMultiLine" : "") 204 ); 205 } 206 207 public static boolean equivalentEditorInfoForKeyboard(final EditorInfo a, final EditorInfo b) { 208 if (a == null && b == null) return true; 209 if (a == null || b == null) return false; 210 return a.inputType == b.inputType 211 && a.imeOptions == b.imeOptions 212 && TextUtils.equals(a.privateImeOptions, b.privateImeOptions); 213 } 214 215 public static String elementIdToName(final int elementId) { 216 switch (elementId) { 217 case ELEMENT_ALPHABET: return "alphabet"; 218 case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted"; 219 case ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: return "alphabetAutomaticShifted"; 220 case ELEMENT_ALPHABET_SHIFT_LOCKED: return "alphabetShiftLocked"; 221 case ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: return "alphabetShiftLockShifted"; 222 case ELEMENT_SYMBOLS: return "symbols"; 223 case ELEMENT_SYMBOLS_SHIFTED: return "symbolsShifted"; 224 case ELEMENT_PHONE: return "phone"; 225 case ELEMENT_PHONE_SYMBOLS: return "phoneSymbols"; 226 case ELEMENT_NUMBER: return "number"; 227 case ELEMENT_EMOJI_RECENTS: return "emojiRecents"; 228 case ELEMENT_EMOJI_CATEGORY1: return "emojiCategory1"; 229 case ELEMENT_EMOJI_CATEGORY2: return "emojiCategory2"; 230 case ELEMENT_EMOJI_CATEGORY3: return "emojiCategory3"; 231 case ELEMENT_EMOJI_CATEGORY4: return "emojiCategory4"; 232 case ELEMENT_EMOJI_CATEGORY5: return "emojiCategory5"; 233 case ELEMENT_EMOJI_CATEGORY6: return "emojiCategory6"; 234 default: return null; 235 } 236 } 237 238 public static String modeName(final int mode) { 239 switch (mode) { 240 case MODE_TEXT: return "text"; 241 case MODE_URL: return "url"; 242 case MODE_EMAIL: return "email"; 243 case MODE_IM: return "im"; 244 case MODE_PHONE: return "phone"; 245 case MODE_NUMBER: return "number"; 246 case MODE_DATE: return "date"; 247 case MODE_TIME: return "time"; 248 case MODE_DATETIME: return "datetime"; 249 default: return null; 250 } 251 } 252 253 public static String actionName(final int actionId) { 254 return (actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel" 255 : EditorInfoCompatUtils.imeActionName(actionId); 256 } 257 } 258