Keyboard.java revision 0ea82be889df77546956c0fe93664622fa4ccb29
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.keyboard;
18
19import android.util.SparseArray;
20
21import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
22import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
23import com.android.inputmethod.keyboard.internal.KeyboardParams;
24import com.android.inputmethod.latin.Constants;
25import com.android.inputmethod.latin.utils.CollectionUtils;
26import com.android.inputmethod.latin.utils.CoordinateUtils;
27
28import java.util.Collections;
29import java.util.List;
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="10%p"
38 *         latin:rowHeight="50px"
39 *         latin:horizontalGap="2%p"
40 *         latin:verticalGap="2%p" &gt;
41 *     &lt;Row latin:keyWidth="10%p" &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 final KeyboardId mId;
51    public final int mThemeId;
52
53    /** Total height of the keyboard, including the padding and keys */
54    public final int mOccupiedHeight;
55    /** Total width of the keyboard, including the padding and keys */
56    public final int mOccupiedWidth;
57
58    /** Base height of the keyboard, used to calculate rows' height */
59    public final int mBaseHeight;
60    /** Base width of the keyboard, used to calculate keys' width */
61    public final int mBaseWidth;
62
63    /** The padding above the keyboard */
64    public final int mTopPadding;
65    /** Default gap between rows */
66    public final int mVerticalGap;
67
68    /** Per keyboard key visual parameters */
69    public final KeyVisualAttributes mKeyVisualAttributes;
70
71    public final int mMostCommonKeyHeight;
72    public final int mMostCommonKeyWidth;
73
74    /** More keys keyboard template */
75    public final int mMoreKeysTemplate;
76
77    /** Maximum column for more keys keyboard */
78    public final int mMaxMoreKeysKeyboardColumn;
79
80    /** List of keys in this keyboard */
81    private final List<Key> mSortedKeys;
82    public final List<Key> mShiftKeys;
83    public final List<Key> mAltCodeKeysWhileTyping;
84    public final KeyboardIconsSet mIconsSet;
85
86    private final SparseArray<Key> mKeyCache = CollectionUtils.newSparseArray();
87
88    private final ProximityInfo mProximityInfo;
89    private final boolean mProximityCharsCorrectionEnabled;
90
91    public Keyboard(final KeyboardParams params) {
92        mId = params.mId;
93        mThemeId = params.mThemeId;
94        mOccupiedHeight = params.mOccupiedHeight;
95        mOccupiedWidth = params.mOccupiedWidth;
96        mBaseHeight = params.mBaseHeight;
97        mBaseWidth = params.mBaseWidth;
98        mMostCommonKeyHeight = params.mMostCommonKeyHeight;
99        mMostCommonKeyWidth = params.mMostCommonKeyWidth;
100        mMoreKeysTemplate = params.mMoreKeysTemplate;
101        mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn;
102        mKeyVisualAttributes = params.mKeyVisualAttributes;
103        mTopPadding = params.mTopPadding;
104        mVerticalGap = params.mVerticalGap;
105
106        mSortedKeys = Collections.unmodifiableList(
107                CollectionUtils.newArrayList(params.mSortedKeys));
108        mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
109        mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping);
110        mIconsSet = params.mIconsSet;
111
112        mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(),
113                params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
114                mMostCommonKeyWidth, mMostCommonKeyHeight, mSortedKeys,
115                params.mTouchPositionCorrection);
116        mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
117    }
118
119    protected Keyboard(final Keyboard keyboard) {
120        mId = keyboard.mId;
121        mThemeId = keyboard.mThemeId;
122        mOccupiedHeight = keyboard.mOccupiedHeight;
123        mOccupiedWidth = keyboard.mOccupiedWidth;
124        mBaseHeight = keyboard.mBaseHeight;
125        mBaseWidth = keyboard.mBaseWidth;
126        mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight;
127        mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth;
128        mMoreKeysTemplate = keyboard.mMoreKeysTemplate;
129        mMaxMoreKeysKeyboardColumn = keyboard.mMaxMoreKeysKeyboardColumn;
130        mKeyVisualAttributes = keyboard.mKeyVisualAttributes;
131        mTopPadding = keyboard.mTopPadding;
132        mVerticalGap = keyboard.mVerticalGap;
133
134        mSortedKeys = keyboard.mSortedKeys;
135        mShiftKeys = keyboard.mShiftKeys;
136        mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping;
137        mIconsSet = keyboard.mIconsSet;
138
139        mProximityInfo = keyboard.mProximityInfo;
140        mProximityCharsCorrectionEnabled = keyboard.mProximityCharsCorrectionEnabled;
141    }
142
143    public boolean hasProximityCharsCorrection(final int code) {
144        if (!mProximityCharsCorrectionEnabled) {
145            return false;
146        }
147        // Note: The native code has the main keyboard layout only at this moment.
148        // TODO: Figure out how to handle proximity characters information of all layouts.
149        final boolean canAssumeNativeHasProximityCharsInfoOfAllKeys = (
150                mId.mElementId == KeyboardId.ELEMENT_ALPHABET
151                || mId.mElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED);
152        return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code);
153    }
154
155    public ProximityInfo getProximityInfo() {
156        return mProximityInfo;
157    }
158
159    /**
160     * Return the sorted list of keys of this keyboard.
161     * The keys are sorted from top-left to bottom-right order.
162     * The list may contain {@link Spacer} object as well.
163     * @return the sorted unmodifiable list of {@link Key}s of this keyboard.
164     */
165    public List<Key> getSortedKeys() {
166        return mSortedKeys;
167    }
168
169    public Key getKey(final int code) {
170        if (code == Constants.CODE_UNSPECIFIED) {
171            return null;
172        }
173        synchronized (mKeyCache) {
174            final int index = mKeyCache.indexOfKey(code);
175            if (index >= 0) {
176                return mKeyCache.valueAt(index);
177            }
178
179            for (final Key key : getSortedKeys()) {
180                if (key.getCode() == code) {
181                    mKeyCache.put(code, key);
182                    return key;
183                }
184            }
185            mKeyCache.put(code, null);
186            return null;
187        }
188    }
189
190    public boolean hasKey(final Key aKey) {
191        if (mKeyCache.indexOfValue(aKey) >= 0) {
192            return true;
193        }
194
195        for (final Key key : getSortedKeys()) {
196            if (key == aKey) {
197                mKeyCache.put(key.getCode(), key);
198                return true;
199            }
200        }
201        return false;
202    }
203
204    @Override
205    public String toString() {
206        return mId.toString();
207    }
208
209    /**
210     * Returns the array of the keys that are closest to the given point.
211     * @param x the x-coordinate of the point
212     * @param y the y-coordinate of the point
213     * @return the list of the nearest keys to the given point. If the given
214     * point is out of range, then an array of size zero is returned.
215     */
216    public List<Key> getNearestKeys(final int x, final int y) {
217        // Avoid dead pixels at edges of the keyboard
218        final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
219        final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
220        return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
221    }
222
223    public int[] getCoordinates(final int[] codePoints) {
224        final int length = codePoints.length;
225        final int[] coordinates = CoordinateUtils.newCoordinateArray(length);
226        for (int i = 0; i < length; ++i) {
227            final Key key = getKey(codePoints[i]);
228            if (null != key) {
229                CoordinateUtils.setXYInArray(coordinates, i,
230                        key.getX() + key.getWidth() / 2, key.getY() + key.getHeight() / 2);
231            } else {
232                CoordinateUtils.setXYInArray(coordinates, i,
233                        Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
234            }
235        }
236        return coordinates;
237    }
238}
239