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