1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * 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.InputTypeUtils; 28 import com.android.inputmethod.latin.SubtypeLocale; 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 58 public static final int FORM_FACTOR_PHONE = 0; 59 public static final int FORM_FACTOR_TABLET7 = 1; 60 public static final int FORM_FACTOR_TABLET10 = 2; 61 62 private static final int IME_ACTION_CUSTOM_LABEL = EditorInfo.IME_MASK_ACTION + 1; 63 64 public final InputMethodSubtype mSubtype; 65 public final Locale mLocale; 66 public final int mDeviceFormFactor; 67 public final int mOrientation; 68 public final int mWidth; 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 mHasShortcutKey; 75 public final boolean mLanguageSwitchKeyEnabled; 76 public final String mCustomActionLabel; 77 78 private final int mHashCode; 79 80 public KeyboardId(int elementId, InputMethodSubtype subtype, int deviceFormFactor, 81 int orientation, int width, int mode, EditorInfo editorInfo, boolean clobberSettingsKey, 82 boolean shortcutKeyEnabled, boolean hasShortcutKey, boolean languageSwitchKeyEnabled) { 83 mSubtype = subtype; 84 mLocale = SubtypeLocale.getSubtypeLocale(subtype); 85 mDeviceFormFactor = deviceFormFactor; 86 mOrientation = orientation; 87 mWidth = width; 88 mMode = mode; 89 mElementId = elementId; 90 mEditorInfo = editorInfo; 91 mClobberSettingsKey = clobberSettingsKey; 92 mShortcutKeyEnabled = shortcutKeyEnabled; 93 mHasShortcutKey = hasShortcutKey; 94 mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled; 95 mCustomActionLabel = (editorInfo.actionLabel != null) 96 ? editorInfo.actionLabel.toString() : null; 97 98 mHashCode = computeHashCode(this); 99 } 100 101 private static int computeHashCode(KeyboardId id) { 102 return Arrays.hashCode(new Object[] { 103 id.mDeviceFormFactor, 104 id.mOrientation, 105 id.mElementId, 106 id.mMode, 107 id.mWidth, 108 id.passwordInput(), 109 id.mClobberSettingsKey, 110 id.mShortcutKeyEnabled, 111 id.mHasShortcutKey, 112 id.mLanguageSwitchKeyEnabled, 113 id.isMultiLine(), 114 id.imeAction(), 115 id.mCustomActionLabel, 116 id.navigateNext(), 117 id.navigatePrevious(), 118 id.mSubtype 119 }); 120 } 121 122 private boolean equals(KeyboardId other) { 123 if (other == this) 124 return true; 125 return other.mDeviceFormFactor == mDeviceFormFactor 126 && other.mOrientation == mOrientation 127 && other.mElementId == mElementId 128 && other.mMode == mMode 129 && other.mWidth == mWidth 130 && other.passwordInput() == passwordInput() 131 && other.mClobberSettingsKey == mClobberSettingsKey 132 && other.mShortcutKeyEnabled == mShortcutKeyEnabled 133 && other.mHasShortcutKey == mHasShortcutKey 134 && other.mLanguageSwitchKeyEnabled == mLanguageSwitchKeyEnabled 135 && other.isMultiLine() == isMultiLine() 136 && other.imeAction() == imeAction() 137 && TextUtils.equals(other.mCustomActionLabel, mCustomActionLabel) 138 && other.navigateNext() == navigateNext() 139 && other.navigatePrevious() == navigatePrevious() 140 && other.mSubtype.equals(mSubtype); 141 } 142 143 public boolean isAlphabetKeyboard() { 144 return mElementId < ELEMENT_SYMBOLS; 145 } 146 147 public boolean navigateNext() { 148 return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0 149 || imeAction() == EditorInfo.IME_ACTION_NEXT; 150 } 151 152 public boolean navigatePrevious() { 153 return (mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0 154 || imeAction() == EditorInfo.IME_ACTION_PREVIOUS; 155 } 156 157 public boolean passwordInput() { 158 final int inputType = mEditorInfo.inputType; 159 return InputTypeUtils.isPasswordInputType(inputType) 160 || InputTypeUtils.isVisiblePasswordInputType(inputType); 161 } 162 163 public boolean isMultiLine() { 164 return (mEditorInfo.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0; 165 } 166 167 public int imeAction() { 168 final int actionId = mEditorInfo.imeOptions & EditorInfo.IME_MASK_ACTION; 169 if ((mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { 170 return EditorInfo.IME_ACTION_NONE; 171 } else if (mEditorInfo.actionLabel != null) { 172 return IME_ACTION_CUSTOM_LABEL; 173 } else { 174 return actionId; 175 } 176 } 177 178 public int imeActionId() { 179 final int actionId = imeAction(); 180 return actionId == IME_ACTION_CUSTOM_LABEL ? mEditorInfo.actionId : actionId; 181 } 182 183 @Override 184 public boolean equals(Object other) { 185 return other instanceof KeyboardId && equals((KeyboardId) other); 186 } 187 188 @Override 189 public int hashCode() { 190 return mHashCode; 191 } 192 193 @Override 194 public String toString() { 195 return String.format("[%s %s:%s %s-%s:%d %s %s %s%s%s%s%s%s%s%s]", 196 elementIdToName(mElementId), 197 mLocale, 198 mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), 199 deviceFormFactor(mDeviceFormFactor), (mOrientation == 1 ? "port" : "land"), mWidth, 200 modeName(mMode), 201 imeAction(), 202 (navigateNext() ? "navigateNext" : ""), 203 (navigatePrevious() ? "navigatePrevious" : ""), 204 (mClobberSettingsKey ? " clobberSettingsKey" : ""), 205 (passwordInput() ? " passwordInput" : ""), 206 (mShortcutKeyEnabled ? " shortcutKeyEnabled" : ""), 207 (mHasShortcutKey ? " hasShortcutKey" : ""), 208 (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""), 209 (isMultiLine() ? "isMultiLine" : "") 210 ); 211 } 212 213 public static boolean equivalentEditorInfoForKeyboard(EditorInfo a, EditorInfo b) { 214 if (a == null && b == null) return true; 215 if (a == null || b == null) return false; 216 return a.inputType == b.inputType 217 && a.imeOptions == b.imeOptions 218 && TextUtils.equals(a.privateImeOptions, b.privateImeOptions); 219 } 220 221 public static String elementIdToName(int elementId) { 222 switch (elementId) { 223 case ELEMENT_ALPHABET: return "alphabet"; 224 case ELEMENT_ALPHABET_MANUAL_SHIFTED: return "alphabetManualShifted"; 225 case ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: return "alphabetAutomaticShifted"; 226 case ELEMENT_ALPHABET_SHIFT_LOCKED: return "alphabetShiftLocked"; 227 case ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: return "alphabetShiftLockShifted"; 228 case ELEMENT_SYMBOLS: return "symbols"; 229 case ELEMENT_SYMBOLS_SHIFTED: return "symbolsShifted"; 230 case ELEMENT_PHONE: return "phone"; 231 case ELEMENT_PHONE_SYMBOLS: return "phoneSymbols"; 232 case ELEMENT_NUMBER: return "number"; 233 default: return null; 234 } 235 } 236 237 public static String deviceFormFactor(int devoceFormFactor) { 238 switch (devoceFormFactor) { 239 case FORM_FACTOR_PHONE: return "phone"; 240 case FORM_FACTOR_TABLET7: return "tablet7"; 241 case FORM_FACTOR_TABLET10: return "tablet10"; 242 default: return null; 243 } 244 } 245 246 public static String modeName(int mode) { 247 switch (mode) { 248 case MODE_TEXT: return "text"; 249 case MODE_URL: return "url"; 250 case MODE_EMAIL: return "email"; 251 case MODE_IM: return "im"; 252 case MODE_PHONE: return "phone"; 253 case MODE_NUMBER: return "number"; 254 case MODE_DATE: return "date"; 255 case MODE_TIME: return "time"; 256 case MODE_DATETIME: return "datetime"; 257 default: return null; 258 } 259 } 260 261 public static String actionName(int actionId) { 262 return (actionId == IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel" 263 : EditorInfoCompatUtils.imeActionName(actionId); 264 } 265 } 266