Home | History | Annotate | Download | only in keyboard
      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 
     17 package com.android.inputmethod.keyboard;
     18 
     19 import android.util.SparseArray;
     20 
     21 import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
     22 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
     23 import com.android.inputmethod.keyboard.internal.KeyboardParams;
     24 import com.android.inputmethod.latin.Constants;
     25 import com.android.inputmethod.latin.utils.CoordinateUtils;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Collections;
     29 import 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  */
     49 public 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 = new SparseArray<>();
     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(new ArrayList<>(params.mSortedKeys));
    107         mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
    108         mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping);
    109         mIconsSet = params.mIconsSet;
    110 
    111         mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(),
    112                 params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
    113                 mMostCommonKeyWidth, mMostCommonKeyHeight, mSortedKeys,
    114                 params.mTouchPositionCorrection);
    115         mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
    116     }
    117 
    118     protected Keyboard(final Keyboard keyboard) {
    119         mId = keyboard.mId;
    120         mThemeId = keyboard.mThemeId;
    121         mOccupiedHeight = keyboard.mOccupiedHeight;
    122         mOccupiedWidth = keyboard.mOccupiedWidth;
    123         mBaseHeight = keyboard.mBaseHeight;
    124         mBaseWidth = keyboard.mBaseWidth;
    125         mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight;
    126         mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth;
    127         mMoreKeysTemplate = keyboard.mMoreKeysTemplate;
    128         mMaxMoreKeysKeyboardColumn = keyboard.mMaxMoreKeysKeyboardColumn;
    129         mKeyVisualAttributes = keyboard.mKeyVisualAttributes;
    130         mTopPadding = keyboard.mTopPadding;
    131         mVerticalGap = keyboard.mVerticalGap;
    132 
    133         mSortedKeys = keyboard.mSortedKeys;
    134         mShiftKeys = keyboard.mShiftKeys;
    135         mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping;
    136         mIconsSet = keyboard.mIconsSet;
    137 
    138         mProximityInfo = keyboard.mProximityInfo;
    139         mProximityCharsCorrectionEnabled = keyboard.mProximityCharsCorrectionEnabled;
    140     }
    141 
    142     public boolean hasProximityCharsCorrection(final int code) {
    143         if (!mProximityCharsCorrectionEnabled) {
    144             return false;
    145         }
    146         // Note: The native code has the main keyboard layout only at this moment.
    147         // TODO: Figure out how to handle proximity characters information of all layouts.
    148         final boolean canAssumeNativeHasProximityCharsInfoOfAllKeys = (
    149                 mId.mElementId == KeyboardId.ELEMENT_ALPHABET
    150                 || mId.mElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED);
    151         return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code);
    152     }
    153 
    154     public ProximityInfo getProximityInfo() {
    155         return mProximityInfo;
    156     }
    157 
    158     /**
    159      * Return the sorted list of keys of this keyboard.
    160      * The keys are sorted from top-left to bottom-right order.
    161      * The list may contain {@link Key.Spacer} object as well.
    162      * @return the sorted unmodifiable list of {@link Key}s of this keyboard.
    163      */
    164     public List<Key> getSortedKeys() {
    165         return mSortedKeys;
    166     }
    167 
    168     public Key getKey(final int code) {
    169         if (code == Constants.CODE_UNSPECIFIED) {
    170             return null;
    171         }
    172         synchronized (mKeyCache) {
    173             final int index = mKeyCache.indexOfKey(code);
    174             if (index >= 0) {
    175                 return mKeyCache.valueAt(index);
    176             }
    177 
    178             for (final Key key : getSortedKeys()) {
    179                 if (key.getCode() == code) {
    180                     mKeyCache.put(code, key);
    181                     return key;
    182                 }
    183             }
    184             mKeyCache.put(code, null);
    185             return null;
    186         }
    187     }
    188 
    189     public boolean hasKey(final Key aKey) {
    190         if (mKeyCache.indexOfValue(aKey) >= 0) {
    191             return true;
    192         }
    193 
    194         for (final Key key : getSortedKeys()) {
    195             if (key == aKey) {
    196                 mKeyCache.put(key.getCode(), key);
    197                 return true;
    198             }
    199         }
    200         return false;
    201     }
    202 
    203     @Override
    204     public String toString() {
    205         return mId.toString();
    206     }
    207 
    208     /**
    209      * Returns the array of the keys that are closest to the given point.
    210      * @param x the x-coordinate of the point
    211      * @param y the y-coordinate of the point
    212      * @return the list of the nearest keys to the given point. If the given
    213      * point is out of range, then an array of size zero is returned.
    214      */
    215     public List<Key> getNearestKeys(final int x, final int y) {
    216         // Avoid dead pixels at edges of the keyboard
    217         final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
    218         final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
    219         return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
    220     }
    221 
    222     public int[] getCoordinates(final int[] codePoints) {
    223         final int length = codePoints.length;
    224         final int[] coordinates = CoordinateUtils.newCoordinateArray(length);
    225         for (int i = 0; i < length; ++i) {
    226             final Key key = getKey(codePoints[i]);
    227             if (null != key) {
    228                 CoordinateUtils.setXYInArray(coordinates, i,
    229                         key.getX() + key.getWidth() / 2, key.getY() + key.getHeight() / 2);
    230             } else {
    231                 CoordinateUtils.setXYInArray(coordinates, i,
    232                         Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
    233             }
    234         }
    235         return coordinates;
    236     }
    237 }
    238