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 public final EditorInfo mEditorInfo; 72 public final boolean mClobberSettingsKey; 73 public final boolean mLanguageSwitchKeyEnabled; 74 public final String mCustomActionLabel; 75 public final boolean mHasShortcutKey; 76 77 private final int mHashCode; 78 79 public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) { 80 mSubtype = params.mSubtype; 81 mLocale = SubtypeLocaleUtils.getSubtypeLocale(mSubtype); 82 mWidth = params.mKeyboardWidth; 83 mHeight = params.mKeyboardHeight; 84 mMode = params.mMode; 85 mElementId = elementId; 86 mEditorInfo = params.mEditorInfo; 87 mClobberSettingsKey = params.mNoSettingsKey; 88 mLanguageSwitchKeyEnabled = params.mLanguageSwitchKeyEnabled; 89 mCustomActionLabel = (mEditorInfo.actionLabel != null) 90 ? mEditorInfo.actionLabel.toString() : null; 91 mHasShortcutKey = params.mVoiceInputKeyEnabled; 92 93 mHashCode = computeHashCode(this); 94 } 95 96 private static int computeHashCode(final KeyboardId id) { 97 return Arrays.hashCode(new Object[] { 98 id.mElementId, 99 id.mMode, 100 id.mWidth, 101 id.mHeight, 102 id.passwordInput(), 103 id.mClobberSettingsKey, 104 id.mHasShortcutKey, 105 id.mLanguageSwitchKeyEnabled, 106 id.isMultiLine(), 107 id.imeAction(), 108 id.mCustomActionLabel, 109 id.navigateNext(), 110 id.navigatePrevious(), 111 id.mSubtype 112 }); 113 } 114 115 private boolean equals(final KeyboardId other) { 116 if (other == this) 117 return true; 118 return other.mElementId == mElementId 119 && other.mMode == mMode 120 && other.mWidth == mWidth 121 && other.mHeight == mHeight 122 && other.passwordInput() == passwordInput() 123 && other.mClobberSettingsKey == mClobberSettingsKey 124 && other.mHasShortcutKey == mHasShortcutKey 125 && other.mLanguageSwitchKeyEnabled == mLanguageSwitchKeyEnabled 126 && other.isMultiLine() == isMultiLine() 127 && other.imeAction() == imeAction() 128 && TextUtils.equals(other.mCustomActionLabel, mCustomActionLabel) 129 && other.navigateNext() == navigateNext() 130 && other.navigatePrevious() == navigatePrevious() 131 && other.mSubtype.equals(mSubtype); 132 } 133 134 private static boolean isAlphabetKeyboard(final int elementId) { 135 return elementId < ELEMENT_SYMBOLS; 136 } 137 138 public boolean isAlphabetKeyboard() { 139 return isAlphabetKeyboard(mElementId); 140 } 141 142 public boolean navigateNext() { 143 return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0 144 || imeAction() == EditorInfo.IME_ACTION_NEXT; 145 } 146 147 public boolean navigatePrevious() { 148 return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0 149 || imeAction() == EditorInfo.IME_ACTION_PREVIOUS; 150 } 151 152 public boolean passwordInput() { 153 final int inputType = mEditorInfo.inputType; 154 return InputTypeUtils.isPasswordInputType(inputType) 155 || InputTypeUtils.isVisiblePasswordInputType(inputType); 156 } 157 158 public boolean isMultiLine() { 159 return (mEditorInfo.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0; 160 } 161 162 public int imeAction() { 163 return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo); 164 } 165 166 @Override 167 public boolean equals(final Object other) { 168 return other instanceof KeyboardId && equals((KeyboardId) other); 169 } 170 171 @Override 172 public int hashCode() { 173 return mHashCode; 174 } 175 176 @Override 177 public String toString() { 178 return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s]", 179 elementIdToName(mElementId), 180 mLocale, mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), 181 mWidth, mHeight, 182 modeName(mMode), 183 actionName(imeAction()), 184 (navigateNext() ? " navigateNext" : ""), 185 (navigatePrevious() ? " navigatePrevious" : ""), 186 (mClobberSettingsKey ? " clobberSettingsKey" : ""), 187 (passwordInput() ? " passwordInput" : ""), 188 (mHasShortcutKey ? " hasShortcutKey" : ""), 189 (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""), 190 (isMultiLine() ? " isMultiLine" : "") 191 ); 192 } 193 194 public static boolean equivalentEditorInfoForKeyboard(final EditorInfo a, final EditorInfo b) { 195 if (a == null && b == null) return true; 196 if (a == null || b == null) return false; 197 return a.inputType == b.inputType 198 && a.imeOptions == b.imeOptions 199 && TextUtils.equals(a.privateImeOptions, b.privateImeOptions); 200 } 201 202 public static String elementIdToName(final int elementId) { 203 switch (elementId) { 204 case ELEMENT_ALPHABET: return "alphabet"; 205 case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted"; 206 case ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: return "alphabetAutomaticShifted"; 207 case ELEMENT_ALPHABET_SHIFT_LOCKED: return "alphabetShiftLocked"; 208 case ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: return "alphabetShiftLockShifted"; 209 case ELEMENT_SYMBOLS: return "symbols"; 210 case ELEMENT_SYMBOLS_SHIFTED: return "symbolsShifted"; 211 case ELEMENT_PHONE: return "phone"; 212 case ELEMENT_PHONE_SYMBOLS: return "phoneSymbols"; 213 case ELEMENT_NUMBER: return "number"; 214 case ELEMENT_EMOJI_RECENTS: return "emojiRecents"; 215 case ELEMENT_EMOJI_CATEGORY1: return "emojiCategory1"; 216 case ELEMENT_EMOJI_CATEGORY2: return "emojiCategory2"; 217 case ELEMENT_EMOJI_CATEGORY3: return "emojiCategory3"; 218 case ELEMENT_EMOJI_CATEGORY4: return "emojiCategory4"; 219 case ELEMENT_EMOJI_CATEGORY5: return "emojiCategory5"; 220 case ELEMENT_EMOJI_CATEGORY6: return "emojiCategory6"; 221 default: return null; 222 } 223 } 224 225 public static String modeName(final int mode) { 226 switch (mode) { 227 case MODE_TEXT: return "text"; 228 case MODE_URL: return "url"; 229 case MODE_EMAIL: return "email"; 230 case MODE_IM: return "im"; 231 case MODE_PHONE: return "phone"; 232 case MODE_NUMBER: return "number"; 233 case MODE_DATE: return "date"; 234 case MODE_TIME: return "time"; 235 case MODE_DATETIME: return "datetime"; 236 default: return null; 237 } 238 } 239 240 public static String actionName(final int actionId) { 241 return (actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel" 242 : EditorInfoCompatUtils.imeActionName(actionId); 243 } 244 } 245