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 android.graphics.drawable.Drawable; 20 import android.text.TextUtils; 21 22 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 23 import com.android.inputmethod.keyboard.internal.KeyboardParams; 24 import com.android.inputmethod.keyboard.internal.KeyboardShiftState; 25 26 import java.util.Collections; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.Set; 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 { 50 /** Some common keys code. These should be aligned with values/keycodes.xml */ 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 = '.'; 55 public static final int CODE_DASH = '-'; 56 public static final int CODE_SINGLE_QUOTE = '\''; 57 public static final int CODE_DOUBLE_QUOTE = '"'; 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 = '>'; 65 public static final int CODE_DIGIT0 = '0'; 66 public static final int CODE_PLUS = '+'; 67 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 public static final int CODE_HAPTIC_AND_AUDIO_FEEDBACK_ONLY = -98; 79 // Code value representing the code is not specified. 80 public static final int CODE_UNSPECIFIED = -99; 81 82 public final KeyboardId mId; 83 public final int mThemeId; 84 85 /** Total height of the keyboard, including the padding and keys */ 86 public final int mOccupiedHeight; 87 /** Total width of the keyboard, including the padding and keys */ 88 public final int mOccupiedWidth; 89 90 /** The padding above the keyboard */ 91 public final int mTopPadding; 92 /** Default gap between rows */ 93 public final int mVerticalGap; 94 95 public final int mMostCommonKeyHeight; 96 public final int mMostCommonKeyWidth; 97 98 /** More keys keyboard template */ 99 public final int mMoreKeysTemplate; 100 101 /** Maximum column for mini keyboard */ 102 public final int mMaxMiniKeyboardColumn; 103 104 /** True if Right-To-Left keyboard */ 105 public final boolean mIsRtlKeyboard; 106 107 /** List of keys and icons in this keyboard */ 108 public final List<Key> mKeys; 109 public final List<Key> mShiftKeys; 110 public final Set<Key> mShiftLockKeys; 111 public final Map<Key, Drawable> mShiftedIcons; 112 public final Map<Key, Drawable> mUnshiftedIcons; 113 public final KeyboardIconsSet mIconsSet; 114 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 boolean hasShiftLockKey() { 150 return !mShiftLockKeys.isEmpty(); 151 } 152 153 public boolean setShiftLocked(boolean newShiftLockState) { 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. 157 key.setHighlightOn(newShiftLockState); 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 } 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) { 174 for (final Key key : mShiftKeys) { 175 if (!newShiftState && !mShiftState.isShiftLocked()) { 176 key.setIcon(mUnshiftedIcons.get(key)); 177 } else if (newShiftState && !mShiftState.isShiftedOrShiftLocked()) { 178 key.setIcon(mShiftedIcons.get(key)); 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 201 public boolean isManualTemporaryUpperCaseFromAuto() { 202 return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCaseFromAuto(); 203 } 204 205 public KeyboardShiftState getKeyboardShiftState() { 206 return mShiftState; 207 } 208 209 public boolean isAlphaKeyboard() { 210 return mId.isAlphabetKeyboard(); 211 } 212 213 public boolean isPhoneKeyboard() { 214 return mId.isPhoneKeyboard(); 215 } 216 217 public boolean isNumberKeyboard() { 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; 227 } 228 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) { 237 return mProximityInfo.getNearestKeys(x, y); 238 } 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 } 252 } 253