blob: 9e4c1ea797da875c86d7172ca134df0a08cd90c6 [file] [log] [blame]
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +09001/*
Tadashi G. Takaoka8632bff2011-05-20 12:09:57 +09002 * Copyright (C) 2010 The Android Open Source Project
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +09003 *
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
Tadashi G. Takaokab7758d62011-06-15 13:38:58 +090019import android.graphics.drawable.Drawable;
Tadashi G. Takaokad773bf32011-06-28 16:32:39 +090020import android.text.TextUtils;
Tadashi G. Takaokab7758d62011-06-15 13:38:58 +090021
Tadashi G. Takaokac2a21782011-06-21 23:38:42 +090022import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -070023import com.android.inputmethod.keyboard.internal.KeyboardParams;
Tadashi G. Takaoka72934bd2011-06-22 11:53:02 +090024import com.android.inputmethod.keyboard.internal.KeyboardShiftState;
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +090025
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -070026import java.util.Collections;
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +090027import java.util.List;
Tadashi G. Takaoka167e77f2011-08-01 17:50:49 -070028import java.util.Map;
29import java.util.Set;
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +090030
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 * &lt;Keyboard
37 * latin:keyWidth="%10p"
38 * latin:keyHeight="50px"
39 * latin:horizontalGap="2px"
40 * latin:verticalGap="2px" &gt;
41 * &lt;Row latin:keyWidth="32px" &gt;
42 * &lt;Key latin:keyLabel="A" /&gt;
43 * ...
44 * &lt;/Row&gt;
45 * ...
46 * &lt;/Keyboard&gt;
47 * </pre>
48 */
49public class Keyboard {
Tadashi G. Takaokae18bd3e2010-12-06 12:12:27 +090050 /** Some common keys code. These should be aligned with values/keycodes.xml */
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +090051 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 Chalard0730bbf2011-04-28 15:39:39 +090055 public static final int CODE_DASH = '-';
56 public static final int CODE_SINGLE_QUOTE = '\'';
57 public static final int CODE_DOUBLE_QUOTE = '"';
Jean Chalard2b4eabe2011-07-14 14:15:01 +090058 // 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. Takaoka851c3262011-07-27 18:02:05 -070065 public static final int CODE_DIGIT0 = '0';
66 public static final int CODE_PLUS = '+';
Jean Chalard2b4eabe2011-07-14 14:15:01 +090067
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +090068
Tadashi G. Takaokae18bd3e2010-12-06 12:12:27 +090069 /** Special keys code. These should be aligned with values/keycodes.xml */
Tadashi G. Takaokac4f71662010-12-20 20:30:26 +090070 public static final int CODE_DUMMY = 0;
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +090071 public static final int CODE_SHIFT = -1;
Tadashi G. Takaokae18bd3e2010-12-06 12:12:27 +090072 public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
Tadashi G. Takaokad2c5fdd2011-04-21 19:43:20 +090073 public static final int CODE_CAPSLOCK = -3;
74 public static final int CODE_CANCEL = -4;
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +090075 public static final int CODE_DELETE = -5;
Tadashi G. Takaokad2c5fdd2011-04-21 19:43:20 +090076 public static final int CODE_SETTINGS = -6;
Ken Wakasacadb2122011-08-06 10:45:19 +090077 public static final int CODE_SHORTCUT = -7;
Tadashi G. Takaokac4f71662010-12-20 20:30:26 +090078 // Code value representing the code is not specified.
79 public static final int CODE_UNSPECIFIED = -99;
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +090080
Tadashi G. Takaoka167e77f2011-08-01 17:50:49 -070081 public final KeyboardId mId;
Tadashi G. Takaoka63584322011-09-28 12:08:48 +090082 public final int mThemeId;
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +090083
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +090084 /** Total height of the keyboard, including the padding and keys */
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -070085 public final int mOccupiedHeight;
86 /** Total width of the keyboard, including the padding and keys */
87 public final int mOccupiedWidth;
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +090088
Tadashi G. Takaoka8fbfac42011-09-22 19:29:58 +090089 /** The padding above the keyboard */
90 public final int mTopPadding;
Tadashi G. Takaoka167e77f2011-08-01 17:50:49 -070091 /** Default gap between rows */
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -070092 public final int mVerticalGap;
93
Tadashi G. Takaoka8fbfac42011-09-22 19:29:58 +090094 public final int mMostCommonKeyHeight;
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -070095 public final int mMostCommonKeyWidth;
Tadashi G. Takaoka167e77f2011-08-01 17:50:49 -070096
Tadashi G. Takaoka9d5601e2011-08-31 15:26:32 +090097 /** More keys keyboard template */
98 public final int mMoreKeysTemplate;
Tadashi G. Takaoka167e77f2011-08-01 17:50:49 -070099
Tadashi G. Takaoka9237a722011-08-31 14:22:53 +0900100 /** Maximum column for mini keyboard */
101 public final int mMaxMiniKeyboardColumn;
Tadashi G. Takaoka167e77f2011-08-01 17:50:49 -0700102
103 /** True if Right-To-Left keyboard */
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -0700104 public final boolean mIsRtlKeyboard;
Tadashi G. Takaoka167e77f2011-08-01 17:50:49 -0700105
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -0700106 /** 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. Takaoka6fb97bf2011-04-15 16:33:46 +0900113
Tadashi G. Takaoka167e77f2011-08-01 17:50:49 -0700114 private final KeyboardShiftState mShiftState = new KeyboardShiftState();
Tadashi G. Takaokac2a21782011-06-21 23:38:42 +0900115
satok8fbd5522011-02-22 17:28:55 +0900116 private final ProximityInfo mProximityInfo;
117
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -0700118 public Keyboard(KeyboardParams params) {
119 mId = params.mId;
Tadashi G. Takaoka63584322011-09-28 12:08:48 +0900120 mThemeId = params.mThemeId;
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -0700121 mOccupiedHeight = params.mOccupiedHeight;
122 mOccupiedWidth = params.mOccupiedWidth;
Tadashi G. Takaoka8fbfac42011-09-22 19:29:58 +0900123 mMostCommonKeyHeight = params.mMostCommonKeyHeight;
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -0700124 mMostCommonKeyWidth = params.mMostCommonKeyWidth;
125 mIsRtlKeyboard = params.mIsRtlKeyboard;
Tadashi G. Takaoka9d5601e2011-08-31 15:26:32 +0900126 mMoreKeysTemplate = params.mMoreKeysTemplate;
Tadashi G. Takaoka9237a722011-08-31 14:22:53 +0900127 mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn;
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +0900128
Tadashi G. Takaoka8fbfac42011-09-22 19:29:58 +0900129 mTopPadding = params.mTopPadding;
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -0700130 mVerticalGap = params.mVerticalGap;
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +0900131
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -0700132 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. Takaoka5a309f52010-12-02 18:46:21 +0900138
satok0d5494c2011-07-12 14:58:46 +0900139 mProximityInfo = new ProximityInfo(
Tadashi G. Takaoka8da9a132011-07-28 17:05:40 -0700140 params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
Yusuke Nojimaad358352011-09-29 16:44:54 +0900141 mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrectionXs,
Yusuke Nojimad6339632011-09-29 11:53:51 +0900142 params.mTouchPositionCorrectionYs, params.mTouchPositionCorrectionRadii);
satok8fbd5522011-02-22 17:28:55 +0900143 }
144
Jean Chalard043f7842011-08-04 12:08:22 +0900145 public ProximityInfo getProximityInfo() {
146 return mProximityInfo;
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +0900147 }
148
Tadashi G. Takaoka6d9bcd52011-07-27 17:20:06 -0700149 public boolean hasShiftLockKey() {
150 return !mShiftLockKeys.isEmpty();
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +0900151 }
152
153 public boolean setShiftLocked(boolean newShiftLockState) {
Tadashi G. Takaoka6d9bcd52011-07-27 17:20:06 -0700154 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. Takaokae7759092011-06-23 21:23:44 +0900157 key.setHighlightOn(newShiftLockState);
Tadashi G. Takaoka6d9bcd52011-07-27 17:20:06 -0700158 // 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. Takaoka571bdb42010-12-02 20:54:32 +0900164 }
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. Takaoka6d9bcd52011-07-27 17:20:06 -0700174 for (final Key key : mShiftKeys) {
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +0900175 if (!newShiftState && !mShiftState.isShiftLocked()) {
Tadashi G. Takaoka6d9bcd52011-07-27 17:20:06 -0700176 key.setIcon(mUnshiftedIcons.get(key));
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +0900177 } else if (newShiftState && !mShiftState.isShiftedOrShiftLocked()) {
Tadashi G. Takaoka6d9bcd52011-07-27 17:20:06 -0700178 key.setIcon(mShiftedIcons.get(key));
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +0900179 }
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. Takaokad01ae892011-01-18 18:12:44 +0900201 public boolean isManualTemporaryUpperCaseFromAuto() {
202 return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCaseFromAuto();
203 }
204
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +0900205 public KeyboardShiftState getKeyboardShiftState() {
206 return mShiftState;
207 }
208
209 public boolean isAlphaKeyboard() {
Tadashi G. Takaokad773bf32011-06-28 16:32:39 +0900210 return mId.isAlphabetKeyboard();
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +0900211 }
212
213 public boolean isPhoneKeyboard() {
Tadashi G. Takaokad773bf32011-06-28 16:32:39 +0900214 return mId.isPhoneKeyboard();
Tadashi G. Takaoka571bdb42010-12-02 20:54:32 +0900215 }
216
217 public boolean isNumberKeyboard() {
Tadashi G. Takaokad773bf32011-06-28 16:32:39 +0900218 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. Takaoka571bdb42010-12-02 20:54:32 +0900227 }
228
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +0900229 /**
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) {
satok0d5494c2011-07-12 14:58:46 +0900237 return mProximityInfo.getNearestKeys(x, y);
Tadashi G. Takaoka5a309f52010-12-02 18:46:21 +0900238 }
Tadashi G. Takaoka63584322011-09-28 12:08:48 +0900239
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. Takaoka5a309f52010-12-02 18:46:21 +0900252}