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