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