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.content.res.Configuration; 22 import android.text.InputType; 23 import android.text.TextUtils; 24 import android.view.inputmethod.EditorInfo; 25 import android.view.inputmethod.InputMethodSubtype; 26 27 import com.android.inputmethod.compat.EditorInfoCompatUtils; 28 import com.android.inputmethod.latin.InputTypeUtils; 29 import com.android.inputmethod.latin.SubtypeLocale; 30 31 import java.util.Arrays; 32 import java.util.Locale; 33 34 /** 35 * Unique identifier for each keyboard type. 36 */ 37 public final class KeyboardId { 38 public static final int MODE_TEXT = 0; 39 public static final int MODE_URL = 1; 40 public static final int MODE_EMAIL = 2; 41 public static final int MODE_IM = 3; 42 public static final int MODE_PHONE = 4; 43 public static final int MODE_NUMBER = 5; 44 public static final int MODE_DATE = 6; 45 public static final int MODE_TIME = 7; 46 public static final int MODE_DATETIME = 8; 47 48 public static final int ELEMENT_ALPHABET = 0; 49 public static final int ELEMENT_ALPHABET_MANUAL_SHIFTED = 1; 50 public static final int ELEMENT_ALPHABET_AUTOMATIC_SHIFTED = 2; 51 public static final int ELEMENT_ALPHABET_SHIFT_LOCKED = 3; 52 public static final int ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED = 4; 53 public static final int ELEMENT_SYMBOLS = 5; 54 public static final int ELEMENT_SYMBOLS_SHIFTED = 6; 55 public static final int ELEMENT_PHONE = 7; 56 public static final int ELEMENT_PHONE_SYMBOLS = 8; 57 public static final int ELEMENT_NUMBER = 9; 58 59 public final InputMethodSubtype mSubtype; 60 public final Locale mLocale; 61 // TODO: Remove this member. It is used only for logging purpose. 62 public final int mOrientation; 63 public final int mWidth; 64 public final int mHeight; 65 public final int mMode; 66 public final int mElementId; 67 private final EditorInfo mEditorInfo; 68 public final boolean mClobberSettingsKey; 69 public final boolean mShortcutKeyEnabled; 70 public final boolean mShortcutKeyOnSymbols; 71 public final boolean mLanguageSwitchKeyEnabled; 72 public final String mCustomActionLabel; 73 public final boolean mHasShortcutKey; 74 75 private final int mHashCode; 76 77 public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) { 78 mSubtype = params.mSubtype; 79 mLocale = SubtypeLocale.getSubtypeLocale(mSubtype); 80 mOrientation = params.mOrientation; 81 mWidth = params.mKeyboardWidth; 82 mHeight = params.mKeyboardHeight; 83 mMode = params.mMode; 84 mElementId = elementId; 85 mEditorInfo = params.mEditorInfo; 86 mClobberSettingsKey = params.mNoSettingsKey; 87 mShortcutKeyEnabled = params.mVoiceKeyEnabled; 88 mShortcutKeyOnSymbols = mShortcutKeyEnabled && !params.mVoiceKeyOnMain; 89 mLanguageSwitchKeyEnabled = params.mLanguageSwitchKeyEnabled; 90 mCustomActionLabel = (mEditorInfo.actionLabel != null) 91 ? mEditorInfo.actionLabel.toString() : null; 92 final boolean alphabetMayHaveShortcutKey = isAlphabetKeyboard(elementId) 93 && !mShortcutKeyOnSymbols; 94 final boolean symbolsMayHaveShortcutKey = (elementId == KeyboardId.ELEMENT_SYMBOLS) 95 && mShortcutKeyOnSymbols; 96 mHasShortcutKey = mShortcutKeyEnabled 97 && (alphabetMayHaveShortcutKey || symbolsMayHaveShortcutKey); 98 99 mHashCode = computeHashCode(this); 100 } 101 102 private static int computeHashCode(final KeyboardId id) { 103 return Arrays.hashCode(new Object[] { 104 id.mOrientation, 105 id.mElementId, 106 id.mMode, 107 id.mWidth, 108 id.mHeight, 109 id.passwordInput(), 110 id.mClobberSettingsKey, 111 id.mShortcutKeyEnabled, 112 id.mShortcutKeyOnSymbols, 113 id.mLanguageSwitchKeyEnabled, 114 id.isMultiLine(), 115 id.imeAction(), 116 id.mCustomActionLabel, 117 id.navigateNext(), 118 id.navigatePrevious(), 119 id.mSubtype 120 }); 121 } 122 123 private boolean equals(final KeyboardId other) { 124 if (other == this) 125 return true; 126 return other.mOrientation == mOrientation 127 && other.mElementId == mElementId 128 && other.mMode == mMode 129 && other.mWidth == mWidth 130 && other.mHeight == mHeight 131 && other.passwordInput() == passwordInput() 132 && other.mClobberSettingsKey == mClobberSettingsKey 133 && other.mShortcutKeyEnabled == mShortcutKeyEnabled 134 && other.mShortcutKeyOnSymbols == mShortcutKeyOnSymbols 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 } 143 144 private static boolean isAlphabetKeyboard(final int elementId) { 145 return elementId < ELEMENT_SYMBOLS; 146 } 147 148 public boolean isAlphabetKeyboard() { 149 return isAlphabetKeyboard(mElementId); 150 } 151 152 public boolean navigateNext() { 153 return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0 154 || imeAction() == EditorInfo.IME_ACTION_NEXT; 155 } 156 157 public boolean navigatePrevious() { 158 return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0 159 || imeAction() == EditorInfo.IME_ACTION_PREVIOUS; 160 } 161 162 public boolean passwordInput() { 163 final int inputType = mEditorInfo.inputType; 164 return InputTypeUtils.isPasswordInputType(inputType) 165 || InputTypeUtils.isVisiblePasswordInputType(inputType); 166 } 167 168 public boolean isMultiLine() { 169 return (mEditorInfo.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0; 170 } 171 172 public int imeAction() { 173 return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo); 174 } 175 176 @Override 177 public boolean equals(final Object other) { 178 return other instanceof KeyboardId && equals((KeyboardId) other); 179 } 180 181 @Override 182 public int hashCode() { 183 return mHashCode; 184 } 185 186 @Override 187 public String toString() { 188 final String orientation = (mOrientation == Configuration.ORIENTATION_PORTRAIT) 189 ? "port" : "land"; 190 return String.format("[%s %s:%s %s:%dx%d %s %s %s%s%s%s%s%s%s%s%s]", 191 elementIdToName(mElementId), 192 mLocale, 193 mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), 194 orientation, mWidth, mHeight, 195 modeName(mMode), 196 imeAction(), 197 (navigateNext() ? "navigateNext" : ""), 198 (navigatePrevious() ? "navigatePrevious" : ""), 199 (mClobberSettingsKey ? " clobberSettingsKey" : ""), 200 (passwordInput() ? " passwordInput" : ""), 201 (mShortcutKeyEnabled ? " shortcutKeyEnabled" : ""), 202 (mShortcutKeyOnSymbols ? " shortcutKeyOnSymbols" : ""), 203 (mHasShortcutKey ? " hasShortcutKey" : ""), 204 (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""), 205 (isMultiLine() ? "isMultiLine" : "") 206 ); 207 } 208 209 public static boolean equivalentEditorInfoForKeyboard(final EditorInfo a, final EditorInfo b) { 210 if (a == null && b == null) return true; 211 if (a == null || b == null) return false; 212 return a.inputType == b.inputType 213 && a.imeOptions == b.imeOptions 214 && TextUtils.equals(a.privateImeOptions, b.privateImeOptions); 215 } 216 217 public static String elementIdToName(final int elementId) { 218 switch (elementId) { 219 case ELEMENT_ALPHABET: return "alphabet"; 220 case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted"; 221 case ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: return "alphabetAutomaticShifted"; 222 case ELEMENT_ALPHABET_SHIFT_LOCKED: return "alphabetShiftLocked"; 223 case ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: return "alphabetShiftLockShifted"; 224 case ELEMENT_SYMBOLS: return "symbols"; 225 case ELEMENT_SYMBOLS_SHIFTED: return "symbolsShifted"; 226 case ELEMENT_PHONE: return "phone"; 227 case ELEMENT_PHONE_SYMBOLS: return "phoneSymbols"; 228 case ELEMENT_NUMBER: return "number"; 229 default: return null; 230 } 231 } 232 233 public static String modeName(final int mode) { 234 switch (mode) { 235 case MODE_TEXT: return "text"; 236 case MODE_URL: return "url"; 237 case MODE_EMAIL: return "email"; 238 case MODE_IM: return "im"; 239 case MODE_PHONE: return "phone"; 240 case MODE_NUMBER: return "number"; 241 case MODE_DATE: return "date"; 242 case MODE_TIME: return "time"; 243 case MODE_DATETIME: return "datetime"; 244 default: return null; 245 } 246 } 247 248 public static String actionName(final int actionId) { 249 return (actionId == InputTypeUtils.IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel" 250 : EditorInfoCompatUtils.imeActionName(actionId); 251 } 252 } 253