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.CollectionUtils; 25 import com.android.inputmethod.latin.Constants; 26 27 /** 28 * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard 29 * consists of rows of keys. 30 * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p> 31 * <pre> 32 * <Keyboard 33 * latin:keyWidth="10%p" 34 * latin:rowHeight="50px" 35 * latin:horizontalGap="2%p" 36 * latin:verticalGap="2%p" > 37 * <Row latin:keyWidth="10%p" > 38 * <Key latin:keyLabel="A" /> 39 * ... 40 * </Row> 41 * ... 42 * </Keyboard> 43 * </pre> 44 */ 45 public class Keyboard { 46 public final KeyboardId mId; 47 public final int mThemeId; 48 49 /** Total height of the keyboard, including the padding and keys */ 50 public final int mOccupiedHeight; 51 /** Total width of the keyboard, including the padding and keys */ 52 public final int mOccupiedWidth; 53 54 /** The padding above the keyboard */ 55 public final int mTopPadding; 56 /** Default gap between rows */ 57 public final int mVerticalGap; 58 59 /** Per keyboard key visual parameters */ 60 public final KeyVisualAttributes mKeyVisualAttributes; 61 62 public final int mMostCommonKeyHeight; 63 public final int mMostCommonKeyWidth; 64 65 /** More keys keyboard template */ 66 public final int mMoreKeysTemplate; 67 68 /** Maximum column for more keys keyboard */ 69 public final int mMaxMoreKeysKeyboardColumn; 70 71 /** Array of keys and icons in this keyboard */ 72 public final Key[] mKeys; 73 public final Key[] mShiftKeys; 74 public final Key[] mAltCodeKeysWhileTyping; 75 public final KeyboardIconsSet mIconsSet; 76 77 private final SparseArray<Key> mKeyCache = CollectionUtils.newSparseArray(); 78 79 private final ProximityInfo mProximityInfo; 80 private final boolean mProximityCharsCorrectionEnabled; 81 82 public Keyboard(final KeyboardParams params) { 83 mId = params.mId; 84 mThemeId = params.mThemeId; 85 mOccupiedHeight = params.mOccupiedHeight; 86 mOccupiedWidth = params.mOccupiedWidth; 87 mMostCommonKeyHeight = params.mMostCommonKeyHeight; 88 mMostCommonKeyWidth = params.mMostCommonKeyWidth; 89 mMoreKeysTemplate = params.mMoreKeysTemplate; 90 mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn; 91 mKeyVisualAttributes = params.mKeyVisualAttributes; 92 mTopPadding = params.mTopPadding; 93 mVerticalGap = params.mVerticalGap; 94 95 mKeys = params.mKeys.toArray(new Key[params.mKeys.size()]); 96 mShiftKeys = params.mShiftKeys.toArray(new Key[params.mShiftKeys.size()]); 97 mAltCodeKeysWhileTyping = params.mAltCodeKeysWhileTyping.toArray( 98 new Key[params.mAltCodeKeysWhileTyping.size()]); 99 mIconsSet = params.mIconsSet; 100 101 mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(), 102 params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, 103 mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection); 104 mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled; 105 } 106 107 public boolean hasProximityCharsCorrection(final int code) { 108 if (!mProximityCharsCorrectionEnabled) { 109 return false; 110 } 111 // Note: The native code has the main keyboard layout only at this moment. 112 // TODO: Figure out how to handle proximity characters information of all layouts. 113 final boolean canAssumeNativeHasProximityCharsInfoOfAllKeys = ( 114 mId.mElementId == KeyboardId.ELEMENT_ALPHABET 115 || mId.mElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED); 116 return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code); 117 } 118 119 public ProximityInfo getProximityInfo() { 120 return mProximityInfo; 121 } 122 123 public Key getKey(final int code) { 124 if (code == Constants.CODE_UNSPECIFIED) { 125 return null; 126 } 127 synchronized (mKeyCache) { 128 final int index = mKeyCache.indexOfKey(code); 129 if (index >= 0) { 130 return mKeyCache.valueAt(index); 131 } 132 133 for (final Key key : mKeys) { 134 if (key.mCode == code) { 135 mKeyCache.put(code, key); 136 return key; 137 } 138 } 139 mKeyCache.put(code, null); 140 return null; 141 } 142 } 143 144 public boolean hasKey(final Key aKey) { 145 if (mKeyCache.indexOfValue(aKey) >= 0) { 146 return true; 147 } 148 149 for (final Key key : mKeys) { 150 if (key == aKey) { 151 mKeyCache.put(key.mCode, key); 152 return true; 153 } 154 } 155 return false; 156 } 157 158 @Override 159 public String toString() { 160 return mId.toString(); 161 } 162 163 /** 164 * Returns the array of the keys that are closest to the given point. 165 * @param x the x-coordinate of the point 166 * @param y the y-coordinate of the point 167 * @return the array of the nearest keys to the given point. If the given 168 * point is out of range, then an array of size zero is returned. 169 */ 170 public Key[] getNearestKeys(final int x, final int y) { 171 // Avoid dead pixels at edges of the keyboard 172 final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1)); 173 final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1)); 174 return mProximityInfo.getNearestKeys(adjustedX, adjustedY); 175 } 176 } 177