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