Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 1 | /* |
Tadashi G. Takaoka | 8632bff | 2011-05-20 12:09:57 +0900 | [diff] [blame] | 2 | * Copyright (C) 2010 The Android Open Source Project |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 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 | |
Tadashi G. Takaoka | b7758d6 | 2011-06-15 13:38:58 +0900 | [diff] [blame] | 19 | import android.graphics.drawable.Drawable; |
Tadashi G. Takaoka | d773bf3 | 2011-06-28 16:32:39 +0900 | [diff] [blame] | 20 | import android.text.TextUtils; |
Tadashi G. Takaoka | b7758d6 | 2011-06-15 13:38:58 +0900 | [diff] [blame] | 21 | |
Tadashi G. Takaoka | c2a2178 | 2011-06-21 23:38:42 +0900 | [diff] [blame] | 22 | import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 23 | import com.android.inputmethod.keyboard.internal.KeyboardParams; |
Tadashi G. Takaoka | 72934bd | 2011-06-22 11:53:02 +0900 | [diff] [blame] | 24 | import com.android.inputmethod.keyboard.internal.KeyboardShiftState; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 25 | |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 26 | import java.util.Collections; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 27 | import java.util.List; |
Tadashi G. Takaoka | 167e77f | 2011-08-01 17:50:49 -0700 | [diff] [blame] | 28 | import java.util.Map; |
| 29 | import java.util.Set; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 30 | |
| 31 | /** |
| 32 | * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard |
| 33 | * consists of rows of keys. |
| 34 | * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p> |
| 35 | * <pre> |
| 36 | * <Keyboard |
| 37 | * latin:keyWidth="%10p" |
| 38 | * latin:keyHeight="50px" |
| 39 | * latin:horizontalGap="2px" |
| 40 | * latin:verticalGap="2px" > |
| 41 | * <Row latin:keyWidth="32px" > |
| 42 | * <Key latin:keyLabel="A" /> |
| 43 | * ... |
| 44 | * </Row> |
| 45 | * ... |
| 46 | * </Keyboard> |
| 47 | * </pre> |
| 48 | */ |
| 49 | public class Keyboard { |
Tadashi G. Takaoka | e18bd3e | 2010-12-06 12:12:27 +0900 | [diff] [blame] | 50 | /** Some common keys code. These should be aligned with values/keycodes.xml */ |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 51 | public static final int CODE_ENTER = '\n'; |
| 52 | public static final int CODE_TAB = '\t'; |
| 53 | public static final int CODE_SPACE = ' '; |
| 54 | public static final int CODE_PERIOD = '.'; |
Jean Chalard | 0730bbf | 2011-04-28 15:39:39 +0900 | [diff] [blame] | 55 | public static final int CODE_DASH = '-'; |
| 56 | public static final int CODE_SINGLE_QUOTE = '\''; |
| 57 | public static final int CODE_DOUBLE_QUOTE = '"'; |
Jean Chalard | 2b4eabe | 2011-07-14 14:15:01 +0900 | [diff] [blame] | 58 | // TODO: Check how this should work for right-to-left languages. It seems to stand |
| 59 | // that for rtl languages, a closing parenthesis is a left parenthesis. Is this |
| 60 | // managed by the font? Or is it a different char? |
| 61 | public static final int CODE_CLOSING_PARENTHESIS = ')'; |
| 62 | public static final int CODE_CLOSING_SQUARE_BRACKET = ']'; |
| 63 | public static final int CODE_CLOSING_CURLY_BRACKET = '}'; |
| 64 | public static final int CODE_CLOSING_ANGLE_BRACKET = '>'; |
Tadashi G. Takaoka | 851c326 | 2011-07-27 18:02:05 -0700 | [diff] [blame] | 65 | public static final int CODE_DIGIT0 = '0'; |
| 66 | public static final int CODE_PLUS = '+'; |
Jean Chalard | 2b4eabe | 2011-07-14 14:15:01 +0900 | [diff] [blame] | 67 | |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 68 | |
Tadashi G. Takaoka | e18bd3e | 2010-12-06 12:12:27 +0900 | [diff] [blame] | 69 | /** Special keys code. These should be aligned with values/keycodes.xml */ |
Tadashi G. Takaoka | c4f7166 | 2010-12-20 20:30:26 +0900 | [diff] [blame] | 70 | public static final int CODE_DUMMY = 0; |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 71 | public static final int CODE_SHIFT = -1; |
Tadashi G. Takaoka | e18bd3e | 2010-12-06 12:12:27 +0900 | [diff] [blame] | 72 | public static final int CODE_SWITCH_ALPHA_SYMBOL = -2; |
Tadashi G. Takaoka | d2c5fdd | 2011-04-21 19:43:20 +0900 | [diff] [blame] | 73 | public static final int CODE_CAPSLOCK = -3; |
| 74 | public static final int CODE_CANCEL = -4; |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 75 | public static final int CODE_DELETE = -5; |
Tadashi G. Takaoka | d2c5fdd | 2011-04-21 19:43:20 +0900 | [diff] [blame] | 76 | public static final int CODE_SETTINGS = -6; |
Ken Wakasa | cadb212 | 2011-08-06 10:45:19 +0900 | [diff] [blame] | 77 | public static final int CODE_SHORTCUT = -7; |
Tadashi G. Takaoka | c4f7166 | 2010-12-20 20:30:26 +0900 | [diff] [blame] | 78 | // Code value representing the code is not specified. |
| 79 | public static final int CODE_UNSPECIFIED = -99; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 80 | |
Tadashi G. Takaoka | 167e77f | 2011-08-01 17:50:49 -0700 | [diff] [blame] | 81 | public final KeyboardId mId; |
Tadashi G. Takaoka | 6358432 | 2011-09-28 12:08:48 +0900 | [diff] [blame] | 82 | public final int mThemeId; |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 83 | |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 84 | /** Total height of the keyboard, including the padding and keys */ |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 85 | public final int mOccupiedHeight; |
| 86 | /** Total width of the keyboard, including the padding and keys */ |
| 87 | public final int mOccupiedWidth; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 88 | |
Tadashi G. Takaoka | 8fbfac4 | 2011-09-22 19:29:58 +0900 | [diff] [blame] | 89 | /** The padding above the keyboard */ |
| 90 | public final int mTopPadding; |
Tadashi G. Takaoka | 167e77f | 2011-08-01 17:50:49 -0700 | [diff] [blame] | 91 | /** Default gap between rows */ |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 92 | public final int mVerticalGap; |
| 93 | |
Tadashi G. Takaoka | 8fbfac4 | 2011-09-22 19:29:58 +0900 | [diff] [blame] | 94 | public final int mMostCommonKeyHeight; |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 95 | public final int mMostCommonKeyWidth; |
Tadashi G. Takaoka | 167e77f | 2011-08-01 17:50:49 -0700 | [diff] [blame] | 96 | |
Tadashi G. Takaoka | 9d5601e | 2011-08-31 15:26:32 +0900 | [diff] [blame] | 97 | /** More keys keyboard template */ |
| 98 | public final int mMoreKeysTemplate; |
Tadashi G. Takaoka | 167e77f | 2011-08-01 17:50:49 -0700 | [diff] [blame] | 99 | |
Tadashi G. Takaoka | 9237a72 | 2011-08-31 14:22:53 +0900 | [diff] [blame] | 100 | /** Maximum column for mini keyboard */ |
| 101 | public final int mMaxMiniKeyboardColumn; |
Tadashi G. Takaoka | 167e77f | 2011-08-01 17:50:49 -0700 | [diff] [blame] | 102 | |
| 103 | /** True if Right-To-Left keyboard */ |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 104 | public final boolean mIsRtlKeyboard; |
Tadashi G. Takaoka | 167e77f | 2011-08-01 17:50:49 -0700 | [diff] [blame] | 105 | |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 106 | /** List of keys and icons in this keyboard */ |
| 107 | public final List<Key> mKeys; |
| 108 | public final List<Key> mShiftKeys; |
| 109 | public final Set<Key> mShiftLockKeys; |
| 110 | public final Map<Key, Drawable> mShiftedIcons; |
| 111 | public final Map<Key, Drawable> mUnshiftedIcons; |
| 112 | public final KeyboardIconsSet mIconsSet; |
Tadashi G. Takaoka | 6fb97bf | 2011-04-15 16:33:46 +0900 | [diff] [blame] | 113 | |
Tadashi G. Takaoka | 167e77f | 2011-08-01 17:50:49 -0700 | [diff] [blame] | 114 | private final KeyboardShiftState mShiftState = new KeyboardShiftState(); |
Tadashi G. Takaoka | c2a2178 | 2011-06-21 23:38:42 +0900 | [diff] [blame] | 115 | |
satok | 8fbd552 | 2011-02-22 17:28:55 +0900 | [diff] [blame] | 116 | private final ProximityInfo mProximityInfo; |
| 117 | |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 118 | public Keyboard(KeyboardParams params) { |
| 119 | mId = params.mId; |
Tadashi G. Takaoka | 6358432 | 2011-09-28 12:08:48 +0900 | [diff] [blame] | 120 | mThemeId = params.mThemeId; |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 121 | mOccupiedHeight = params.mOccupiedHeight; |
| 122 | mOccupiedWidth = params.mOccupiedWidth; |
Tadashi G. Takaoka | 8fbfac4 | 2011-09-22 19:29:58 +0900 | [diff] [blame] | 123 | mMostCommonKeyHeight = params.mMostCommonKeyHeight; |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 124 | mMostCommonKeyWidth = params.mMostCommonKeyWidth; |
| 125 | mIsRtlKeyboard = params.mIsRtlKeyboard; |
Tadashi G. Takaoka | 9d5601e | 2011-08-31 15:26:32 +0900 | [diff] [blame] | 126 | mMoreKeysTemplate = params.mMoreKeysTemplate; |
Tadashi G. Takaoka | 9237a72 | 2011-08-31 14:22:53 +0900 | [diff] [blame] | 127 | mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 128 | |
Tadashi G. Takaoka | 8fbfac4 | 2011-09-22 19:29:58 +0900 | [diff] [blame] | 129 | mTopPadding = params.mTopPadding; |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 130 | mVerticalGap = params.mVerticalGap; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 131 | |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 132 | mKeys = Collections.unmodifiableList(params.mKeys); |
| 133 | mShiftKeys = Collections.unmodifiableList(params.mShiftKeys); |
| 134 | mShiftLockKeys = Collections.unmodifiableSet(params.mShiftLockKeys); |
| 135 | mShiftedIcons = Collections.unmodifiableMap(params.mShiftedIcons); |
| 136 | mUnshiftedIcons = Collections.unmodifiableMap(params.mUnshiftedIcons); |
| 137 | mIconsSet = params.mIconsSet; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 138 | |
satok | 0d5494c | 2011-07-12 14:58:46 +0900 | [diff] [blame] | 139 | mProximityInfo = new ProximityInfo( |
Tadashi G. Takaoka | 8da9a13 | 2011-07-28 17:05:40 -0700 | [diff] [blame] | 140 | params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, |
Yusuke Nojima | ad35835 | 2011-09-29 16:44:54 +0900 | [diff] [blame^] | 141 | mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrectionXs, |
Yusuke Nojima | d633963 | 2011-09-29 11:53:51 +0900 | [diff] [blame] | 142 | params.mTouchPositionCorrectionYs, params.mTouchPositionCorrectionRadii); |
satok | 8fbd552 | 2011-02-22 17:28:55 +0900 | [diff] [blame] | 143 | } |
| 144 | |
Jean Chalard | 043f784 | 2011-08-04 12:08:22 +0900 | [diff] [blame] | 145 | public ProximityInfo getProximityInfo() { |
| 146 | return mProximityInfo; |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 147 | } |
| 148 | |
Tadashi G. Takaoka | 6d9bcd5 | 2011-07-27 17:20:06 -0700 | [diff] [blame] | 149 | public boolean hasShiftLockKey() { |
| 150 | return !mShiftLockKeys.isEmpty(); |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | public boolean setShiftLocked(boolean newShiftLockState) { |
Tadashi G. Takaoka | 6d9bcd5 | 2011-07-27 17:20:06 -0700 | [diff] [blame] | 154 | for (final Key key : mShiftLockKeys) { |
| 155 | // To represent "shift locked" state. The highlight is handled by background image that |
| 156 | // might be a StateListDrawable. |
Tadashi G. Takaoka | e775909 | 2011-06-23 21:23:44 +0900 | [diff] [blame] | 157 | key.setHighlightOn(newShiftLockState); |
Tadashi G. Takaoka | 6d9bcd5 | 2011-07-27 17:20:06 -0700 | [diff] [blame] | 158 | // To represent "shifted" state. The key might have a shifted icon. |
| 159 | if (newShiftLockState && mShiftedIcons.containsKey(key)) { |
| 160 | key.setIcon(mShiftedIcons.get(key)); |
| 161 | } else { |
| 162 | key.setIcon(mUnshiftedIcons.get(key)); |
| 163 | } |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 164 | } |
| 165 | mShiftState.setShiftLocked(newShiftLockState); |
| 166 | return true; |
| 167 | } |
| 168 | |
| 169 | public boolean isShiftLocked() { |
| 170 | return mShiftState.isShiftLocked(); |
| 171 | } |
| 172 | |
| 173 | public boolean setShifted(boolean newShiftState) { |
Tadashi G. Takaoka | 6d9bcd5 | 2011-07-27 17:20:06 -0700 | [diff] [blame] | 174 | for (final Key key : mShiftKeys) { |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 175 | if (!newShiftState && !mShiftState.isShiftLocked()) { |
Tadashi G. Takaoka | 6d9bcd5 | 2011-07-27 17:20:06 -0700 | [diff] [blame] | 176 | key.setIcon(mUnshiftedIcons.get(key)); |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 177 | } else if (newShiftState && !mShiftState.isShiftedOrShiftLocked()) { |
Tadashi G. Takaoka | 6d9bcd5 | 2011-07-27 17:20:06 -0700 | [diff] [blame] | 178 | key.setIcon(mShiftedIcons.get(key)); |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 179 | } |
| 180 | } |
| 181 | return mShiftState.setShifted(newShiftState); |
| 182 | } |
| 183 | |
| 184 | public boolean isShiftedOrShiftLocked() { |
| 185 | return mShiftState.isShiftedOrShiftLocked(); |
| 186 | } |
| 187 | |
| 188 | public void setAutomaticTemporaryUpperCase() { |
| 189 | setShifted(true); |
| 190 | mShiftState.setAutomaticTemporaryUpperCase(); |
| 191 | } |
| 192 | |
| 193 | public boolean isAutomaticTemporaryUpperCase() { |
| 194 | return isAlphaKeyboard() && mShiftState.isAutomaticTemporaryUpperCase(); |
| 195 | } |
| 196 | |
| 197 | public boolean isManualTemporaryUpperCase() { |
| 198 | return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase(); |
| 199 | } |
| 200 | |
Tadashi G. Takaoka | d01ae89 | 2011-01-18 18:12:44 +0900 | [diff] [blame] | 201 | public boolean isManualTemporaryUpperCaseFromAuto() { |
| 202 | return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCaseFromAuto(); |
| 203 | } |
| 204 | |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 205 | public KeyboardShiftState getKeyboardShiftState() { |
| 206 | return mShiftState; |
| 207 | } |
| 208 | |
| 209 | public boolean isAlphaKeyboard() { |
Tadashi G. Takaoka | d773bf3 | 2011-06-28 16:32:39 +0900 | [diff] [blame] | 210 | return mId.isAlphabetKeyboard(); |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | public boolean isPhoneKeyboard() { |
Tadashi G. Takaoka | d773bf3 | 2011-06-28 16:32:39 +0900 | [diff] [blame] | 214 | return mId.isPhoneKeyboard(); |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 215 | } |
| 216 | |
| 217 | public boolean isNumberKeyboard() { |
Tadashi G. Takaoka | d773bf3 | 2011-06-28 16:32:39 +0900 | [diff] [blame] | 218 | return mId.isNumberKeyboard(); |
| 219 | } |
| 220 | |
| 221 | public CharSequence adjustLabelCase(CharSequence label) { |
| 222 | if (isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) && label.length() < 3 |
| 223 | && Character.isLowerCase(label.charAt(0))) { |
| 224 | return label.toString().toUpperCase(mId.mLocale); |
| 225 | } |
| 226 | return label; |
Tadashi G. Takaoka | 571bdb4 | 2010-12-02 20:54:32 +0900 | [diff] [blame] | 227 | } |
| 228 | |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 229 | /** |
| 230 | * Returns the indices of the keys that are closest to the given point. |
| 231 | * @param x the x-coordinate of the point |
| 232 | * @param y the y-coordinate of the point |
| 233 | * @return the array of integer indices for the nearest keys to the given point. If the given |
| 234 | * point is out of range, then an array of size zero is returned. |
| 235 | */ |
| 236 | public int[] getNearestKeys(int x, int y) { |
satok | 0d5494c | 2011-07-12 14:58:46 +0900 | [diff] [blame] | 237 | return mProximityInfo.getNearestKeys(x, y); |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 238 | } |
Tadashi G. Takaoka | 6358432 | 2011-09-28 12:08:48 +0900 | [diff] [blame] | 239 | |
| 240 | public static String themeName(int themeId) { |
| 241 | // This should be aligned with theme-*.xml resource files' themeId attribute. |
| 242 | switch (themeId) { |
| 243 | case 0: return "Basic"; |
| 244 | case 1: return "BasicHighContrast"; |
| 245 | case 5: return "IceCreamSandwich"; |
| 246 | case 6: return "Stone"; |
| 247 | case 7: return "StoneBold"; |
| 248 | case 8: return "GingerBread"; |
| 249 | default: return null; |
| 250 | } |
| 251 | } |
Tadashi G. Takaoka | 5a309f5 | 2010-12-02 18:46:21 +0900 | [diff] [blame] | 252 | } |