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.common.Constants;
     25 import com.android.inputmethod.latin.common.CoordinateUtils;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Collections;
     29 import java.util.List;
     30 
     31 import javax.annotation.Nonnull;
     32 import javax.annotation.Nullable;
     33 
     34 /**
     35  * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
     36  * consists of rows of keys.
     37  * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p>
     38  * <pre>
     39  * &lt;Keyboard
     40  *         latin:keyWidth="10%p"
     41  *         latin:rowHeight="50px"
     42  *         latin:horizontalGap="2%p"
     43  *         latin:verticalGap="2%p" &gt;
     44  *     &lt;Row latin:keyWidth="10%p" &gt;
     45  *         &lt;Key latin:keyLabel="A" /&gt;
     46  *         ...
     47  *     &lt;/Row&gt;
     48  *     ...
     49  * &lt;/Keyboard&gt;
     50  * </pre>
     51  */
     52 public class Keyboard {
     53     @Nonnull
     54     public final KeyboardId mId;
     55     public final int mThemeId;
     56 
     57     /** Total height of the keyboard, including the padding and keys */
     58     public final int mOccupiedHeight;
     59     /** Total width of the keyboard, including the padding and keys */
     60     public final int mOccupiedWidth;
     61 
     62     /** Base height of the keyboard, used to calculate rows' height */
     63     public final int mBaseHeight;
     64     /** Base width of the keyboard, used to calculate keys' width */
     65     public final int mBaseWidth;
     66 
     67     /** The padding above the keyboard */
     68     public final int mTopPadding;
     69     /** Default gap between rows */
     70     public final int mVerticalGap;
     71 
     72     /** Per keyboard key visual parameters */
     73     public final KeyVisualAttributes mKeyVisualAttributes;
     74 
     75     public final int mMostCommonKeyHeight;
     76     public final int mMostCommonKeyWidth;
     77 
     78     /** More keys keyboard template */
     79     public final int mMoreKeysTemplate;
     80 
     81     /** Maximum column for more keys keyboard */
     82     public final int mMaxMoreKeysKeyboardColumn;
     83 
     84     /** List of keys in this keyboard */
     85     @Nonnull
     86     private final List<Key> mSortedKeys;
     87     @Nonnull
     88     public final List<Key> mShiftKeys;
     89     @Nonnull
     90     public final List<Key> mAltCodeKeysWhileTyping;
     91     @Nonnull
     92     public final KeyboardIconsSet mIconsSet;
     93 
     94     private final SparseArray<Key> mKeyCache = new SparseArray<>();
     95 
     96     @Nonnull
     97     private final ProximityInfo mProximityInfo;
     98     @Nonnull
     99     private final KeyboardLayout mKeyboardLayout;
    100 
    101     private final boolean mProximityCharsCorrectionEnabled;
    102 
    103     public Keyboard(@Nonnull final KeyboardParams params) {
    104         mId = params.mId;
    105         mThemeId = params.mThemeId;
    106         mOccupiedHeight = params.mOccupiedHeight;
    107         mOccupiedWidth = params.mOccupiedWidth;
    108         mBaseHeight = params.mBaseHeight;
    109         mBaseWidth = params.mBaseWidth;
    110         mMostCommonKeyHeight = params.mMostCommonKeyHeight;
    111         mMostCommonKeyWidth = params.mMostCommonKeyWidth;
    112         mMoreKeysTemplate = params.mMoreKeysTemplate;
    113         mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn;
    114         mKeyVisualAttributes = params.mKeyVisualAttributes;
    115         mTopPadding = params.mTopPadding;
    116         mVerticalGap = params.mVerticalGap;
    117 
    118         mSortedKeys = Collections.unmodifiableList(new ArrayList<>(params.mSortedKeys));
    119         mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
    120         mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping);
    121         mIconsSet = params.mIconsSet;
    122 
    123         mProximityInfo = new ProximityInfo(params.GRID_WIDTH, params.GRID_HEIGHT,
    124                 mOccupiedWidth, mOccupiedHeight, mMostCommonKeyWidth, mMostCommonKeyHeight,
    125                 mSortedKeys, params.mTouchPositionCorrection);
    126         mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
    127         mKeyboardLayout = KeyboardLayout.newKeyboardLayout(mSortedKeys, mMostCommonKeyWidth,
    128                 mMostCommonKeyHeight, mOccupiedWidth, mOccupiedHeight);
    129     }
    130 
    131     protected Keyboard(@Nonnull final Keyboard keyboard) {
    132         mId = keyboard.mId;
    133         mThemeId = keyboard.mThemeId;
    134         mOccupiedHeight = keyboard.mOccupiedHeight;
    135         mOccupiedWidth = keyboard.mOccupiedWidth;
    136         mBaseHeight = keyboard.mBaseHeight;
    137         mBaseWidth = keyboard.mBaseWidth;
    138         mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight;
    139         mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth;
    140         mMoreKeysTemplate = keyboard.mMoreKeysTemplate;
    141         mMaxMoreKeysKeyboardColumn = keyboard.mMaxMoreKeysKeyboardColumn;
    142         mKeyVisualAttributes = keyboard.mKeyVisualAttributes;
    143         mTopPadding = keyboard.mTopPadding;
    144         mVerticalGap = keyboard.mVerticalGap;
    145 
    146         mSortedKeys = keyboard.mSortedKeys;
    147         mShiftKeys = keyboard.mShiftKeys;
    148         mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping;
    149         mIconsSet = keyboard.mIconsSet;
    150 
    151         mProximityInfo = keyboard.mProximityInfo;
    152         mProximityCharsCorrectionEnabled = keyboard.mProximityCharsCorrectionEnabled;
    153         mKeyboardLayout = keyboard.mKeyboardLayout;
    154     }
    155 
    156     public boolean hasProximityCharsCorrection(final int code) {
    157         if (!mProximityCharsCorrectionEnabled) {
    158             return false;
    159         }
    160         // Note: The native code has the main keyboard layout only at this moment.
    161         // TODO: Figure out how to handle proximity characters information of all layouts.
    162         final boolean canAssumeNativeHasProximityCharsInfoOfAllKeys = (
    163                 mId.mElementId == KeyboardId.ELEMENT_ALPHABET
    164                 || mId.mElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED);
    165         return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code);
    166     }
    167 
    168     @Nonnull
    169     public ProximityInfo getProximityInfo() {
    170         return mProximityInfo;
    171     }
    172 
    173     @Nonnull
    174     public KeyboardLayout getKeyboardLayout() {
    175         return mKeyboardLayout;
    176     }
    177 
    178     /**
    179      * Return the sorted list of keys of this keyboard.
    180      * The keys are sorted from top-left to bottom-right order.
    181      * The list may contain {@link Key.Spacer} object as well.
    182      * @return the sorted unmodifiable list of {@link Key}s of this keyboard.
    183      */
    184     @Nonnull
    185     public List<Key> getSortedKeys() {
    186         return mSortedKeys;
    187     }
    188 
    189     @Nullable
    190     public Key getKey(final int code) {
    191         if (code == Constants.CODE_UNSPECIFIED) {
    192             return null;
    193         }
    194         synchronized (mKeyCache) {
    195             final int index = mKeyCache.indexOfKey(code);
    196             if (index >= 0) {
    197                 return mKeyCache.valueAt(index);
    198             }
    199 
    200             for (final Key key : getSortedKeys()) {
    201                 if (key.getCode() == code) {
    202                     mKeyCache.put(code, key);
    203                     return key;
    204                 }
    205             }
    206             mKeyCache.put(code, null);
    207             return null;
    208         }
    209     }
    210 
    211     public boolean hasKey(@Nonnull final Key aKey) {
    212         if (mKeyCache.indexOfValue(aKey) >= 0) {
    213             return true;
    214         }
    215 
    216         for (final Key key : getSortedKeys()) {
    217             if (key == aKey) {
    218                 mKeyCache.put(key.getCode(), key);
    219                 return true;
    220             }
    221         }
    222         return false;
    223     }
    224 
    225     @Override
    226     public String toString() {
    227         return mId.toString();
    228     }
    229 
    230     /**
    231      * Returns the array of the keys that are closest to the given point.
    232      * @param x the x-coordinate of the point
    233      * @param y the y-coordinate of the point
    234      * @return the list of the nearest keys to the given point. If the given
    235      * point is out of range, then an array of size zero is returned.
    236      */
    237     @Nonnull
    238     public List<Key> getNearestKeys(final int x, final int y) {
    239         // Avoid dead pixels at edges of the keyboard
    240         final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
    241         final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1));
    242         return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
    243     }
    244 
    245     @Nonnull
    246     public int[] getCoordinates(@Nonnull final int[] codePoints) {
    247         final int length = codePoints.length;
    248         final int[] coordinates = CoordinateUtils.newCoordinateArray(length);
    249         for (int i = 0; i < length; ++i) {
    250             final Key key = getKey(codePoints[i]);
    251             if (null != key) {
    252                 CoordinateUtils.setXYInArray(coordinates, i,
    253                         key.getX() + key.getWidth() / 2, key.getY() + key.getHeight() / 2);
    254             } else {
    255                 CoordinateUtils.setXYInArray(coordinates, i,
    256                         Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
    257             }
    258         }
    259         return coordinates;
    260     }
    261 }
    262