Keyboard.java revision 1e4684ad24914cde713980bb4174810bbf8bae10
15a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka/* 28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 35a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * 45a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); you may not 55a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * use this file except in compliance with the License. You may obtain a copy of 65a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * the License at 75a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * 85a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 95a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * 105a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 115a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 125a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 135a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * License for the specific language governing permissions and limitations under 145a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * the License. 155a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka */ 165a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 185a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.content.Context; 204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.content.res.Resources; 214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.content.res.TypedArray; 224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.content.res.XmlResourceParser; 23d773bf38a3c8f49ea56de67d3b828f8126f46ed2Tadashi G. Takaokaimport android.text.TextUtils; 244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.util.DisplayMetrics; 257dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaokaimport android.util.Log; 264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.util.TypedValue; 274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.util.Xml; 284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.view.InflateException; 295a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.compat.EditorInfoCompatUtils; 314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyStyles; 32c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 33e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardShiftState; 344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.latin.XmlParseUtils; 37b7758d6f912093747d4b18fbc8d1dcd77c7d1f9bTadashi G. Takaoka 384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport org.xmlpull.v1.XmlPullParser; 394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport org.xmlpull.v1.XmlPullParserException; 404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport java.io.IOException; 424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport java.util.Arrays; 438da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaokaimport java.util.Collections; 442013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaokaimport java.util.HashMap; 454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport java.util.HashSet; 46167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaokaimport java.util.Map; 47167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaokaimport java.util.Set; 485a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 495a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka/** 505a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard 515a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * consists of rows of keys. 525a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p> 535a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <pre> 545a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Keyboard 555a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:keyWidth="%10p" 565a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:keyHeight="50px" 575a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:horizontalGap="2px" 585a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:verticalGap="2px" > 595a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Row latin:keyWidth="32px" > 605a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Key latin:keyLabel="A" /> 615a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * ... 625a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </Row> 635a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * ... 645a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </Keyboard> 655a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </pre> 665a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka */ 675a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapublic class Keyboard { 687dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka private static final String TAG = Keyboard.class.getSimpleName(); 697dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka 70ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka /** Some common keys code. Must be positive. 71ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka * These should be aligned with values/keycodes.xml 72ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka */ 73571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_ENTER = '\n'; 74571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_TAB = '\t'; 75571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_SPACE = ' '; 76571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_PERIOD = '.'; 770730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_DASH = '-'; 780730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_SINGLE_QUOTE = '\''; 790730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_DOUBLE_QUOTE = '"'; 802b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // TODO: Check how this should work for right-to-left languages. It seems to stand 812b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // that for rtl languages, a closing parenthesis is a left parenthesis. Is this 822b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // managed by the font? Or is it a different char? 832b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_PARENTHESIS = ')'; 842b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_SQUARE_BRACKET = ']'; 852b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_CURLY_BRACKET = '}'; 862b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_ANGLE_BRACKET = '>'; 87851c3267d4ab21f892b4164783bb4959c88b44ffTadashi G. Takaoka public static final int CODE_DIGIT0 = '0'; 88851c3267d4ab21f892b4164783bb4959c88b44ffTadashi G. Takaoka public static final int CODE_PLUS = '+'; 898cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka private static final int MINIMUM_LETTER_CODE = CODE_TAB; 902b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard 918cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka /** Special keys code. Must be negative. 92ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka * These should be aligned with values/keycodes.xml 93ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka */ 94571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_SHIFT = -1; 95e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka public static final int CODE_SWITCH_ALPHA_SYMBOL = -2; 96d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka public static final int CODE_CAPSLOCK = -3; 978cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka public static final int CODE_OUTPUT_TEXT = -4; 98571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_DELETE = -5; 99d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka public static final int CODE_SETTINGS = -6; 100cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public static final int CODE_SHORTCUT = -7; 101c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka // Code value representing the code is not specified. 1028cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka public static final int CODE_UNSPECIFIED = -9; 1035a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 104167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka public final KeyboardId mId; 10563584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka public final int mThemeId; 106167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka 107167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka /** Total height of the keyboard, including the padding and keys */ 1088da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mOccupiedHeight; 1098da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka /** Total width of the keyboard, including the padding and keys */ 1108da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mOccupiedWidth; 111167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka 1128fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka /** The padding above the keyboard */ 1138fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka public final int mTopPadding; 1145a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka /** Default gap between rows */ 1158da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mVerticalGap; 1168da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1178fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka public final int mMostCommonKeyHeight; 1188da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mMostCommonKeyWidth; 1195a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1209d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka /** More keys keyboard template */ 1219d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public final int mMoreKeysTemplate; 1229b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka 1239237a72634be821c22911633ef0848130e162d58Tadashi G. Takaoka /** Maximum column for mini keyboard */ 1249237a72634be821c22911633ef0848130e162d58Tadashi G. Takaoka public final int mMaxMiniKeyboardColumn; 1259b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka 1267139335dcd84209285c028f5d83cb72bfbf1a966Tadashi G. Takaoka /** True if Right-To-Left keyboard */ 1278da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final boolean mIsRtlKeyboard; 1285a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1298da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka /** List of keys and icons in this keyboard */ 1304a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka public final Set<Key> mKeys; 1314a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka public final Set<Key> mShiftKeys; 1328da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final Set<Key> mShiftLockKeys; 1338da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final KeyboardIconsSet mIconsSet; 1346fb97bf71cee2a0775410a05478ed6a667aa847fTadashi G. Takaoka 1352013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>(); 136c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 1378fbd55229243cb66c03d5ea1f79dfb39f596590dsatok private final ProximityInfo mProximityInfo; 1388fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 139e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaoka // TODO: Remove this variable. 140e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaoka private final KeyboardShiftState mShiftState = new KeyboardShiftState(); 141c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka 1424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Keyboard(Params params) { 1438da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mId = params.mId; 14463584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka mThemeId = params.mThemeId; 1458da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mOccupiedHeight = params.mOccupiedHeight; 1468da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mOccupiedWidth = params.mOccupiedWidth; 1478fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka mMostCommonKeyHeight = params.mMostCommonKeyHeight; 1488da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mMostCommonKeyWidth = params.mMostCommonKeyWidth; 1498da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mIsRtlKeyboard = params.mIsRtlKeyboard; 1509d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysTemplate = params.mMoreKeysTemplate; 1519237a72634be821c22911633ef0848130e162d58Tadashi G. Takaoka mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn; 1528da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1538fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka mTopPadding = params.mTopPadding; 1548da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mVerticalGap = params.mVerticalGap; 1558da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1564a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka mKeys = Collections.unmodifiableSet(params.mKeys); 1574a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys); 1588da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mShiftLockKeys = Collections.unmodifiableSet(params.mShiftLockKeys); 1598da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mIconsSet = params.mIconsSet; 1605a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1610d5494c66ac3e5947040e8148091163a1c8716f7satok mProximityInfo = new ProximityInfo( 1628da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, 163294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection); 1648fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1658fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 166043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard public ProximityInfo getProximityInfo() { 167043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard return mProximityInfo; 1685a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 1695a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1702013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka public Key getKey(int code) { 1718cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka if (code == CODE_UNSPECIFIED) { 172623d0155b6a316fdc9335370cdd4005bbb474ef3Tadashi G. Takaoka return null; 173623d0155b6a316fdc9335370cdd4005bbb474ef3Tadashi G. Takaoka } 1742013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka final Integer keyCode = code; 1752013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (mKeyCache.containsKey(keyCode)) { 1762013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return mKeyCache.get(keyCode); 1772013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1782013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 1792013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka for (final Key key : mKeys) { 1802013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (key.mCode == code) { 1812013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka mKeyCache.put(keyCode, key); 1822013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return key; 1832013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1842013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1852013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka mKeyCache.put(keyCode, null); 1862013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return null; 1872013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1882013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 189c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method. 1904a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka boolean hasShiftLockKey() { 1916d9bcd5e1317722207116ab6a3ddfcb152005701Tadashi G. Takaoka return !mShiftLockKeys.isEmpty(); 192571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 193571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 194c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method. 1954a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka void setShiftLocked(boolean newShiftLockState) { 1966d9bcd5e1317722207116ab6a3ddfcb152005701Tadashi G. Takaoka for (final Key key : mShiftLockKeys) { 1976d9bcd5e1317722207116ab6a3ddfcb152005701Tadashi G. Takaoka // To represent "shift locked" state. The highlight is handled by background image that 1986d9bcd5e1317722207116ab6a3ddfcb152005701Tadashi G. Takaoka // might be a StateListDrawable. 199e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka key.setHighlightOn(newShiftLockState); 20042fcb2de641c4cd5d57f34889c8752401e35dcc8Tadashi G. Takaoka final int attrId = newShiftLockState 20142fcb2de641c4cd5d57f34889c8752401e35dcc8Tadashi G. Takaoka ? R.styleable.Keyboard_iconShiftKeyShifted 20242fcb2de641c4cd5d57f34889c8752401e35dcc8Tadashi G. Takaoka : R.styleable.Keyboard_iconShiftKey; 20342fcb2de641c4cd5d57f34889c8752401e35dcc8Tadashi G. Takaoka key.setIcon(mIconsSet.getIconByAttrId(attrId)); 204571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 205e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaoka mShiftState.setShiftLocked(newShiftLockState); 206571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 207571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 208c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Move this method to KeyboardId. 209571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public boolean isShiftLocked() { 210e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaoka return mShiftState.isShiftLocked(); 211571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 212571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 21307145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka private void setShiftKeyGraphics(boolean newShiftState) { 21407145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka if (mShiftState.isShiftLocked()) { 21507145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka return; 21607145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka } 21707145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka for (final Key key : mShiftKeys) { 21807145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka final int attrId = newShiftState 21907145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka ? R.styleable.Keyboard_iconShiftKeyShifted 22007145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka : R.styleable.Keyboard_iconShiftKey; 22107145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka key.setIcon(mIconsSet.getIconByAttrId(attrId)); 22207145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka } 22307145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka } 22407145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka 225c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method. 2264a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka void setShifted(boolean newShiftState) { 22707145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka setShiftKeyGraphics(newShiftState); 228e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaoka mShiftState.setShifted(newShiftState); 2295a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 2305a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 231c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Move this method to KeyboardId. 2325a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka public boolean isShiftedOrShiftLocked() { 233e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaoka return mShiftState.isShiftedOrShiftLocked(); 2345a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 2355a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 236c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method 2374a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka void setAutomaticTemporaryUpperCase() { 23807145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka setShiftKeyGraphics(true); 239e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaoka mShiftState.setAutomaticTemporaryUpperCase(); 240571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 241571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 242c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Move this method to KeyboardId. 243571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public boolean isManualTemporaryUpperCase() { 244e466583ddc68278ad708094f8ac521be504bf342Tadashi G. Takaoka return mShiftState.isManualTemporaryUpperCase(); 245571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 246571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 247c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method. 248d773bf38a3c8f49ea56de67d3b828f8126f46ed2Tadashi G. Takaoka public CharSequence adjustLabelCase(CharSequence label) { 2491ebedd7a15a8fd94e68fb43eb089ed87c4c5a480Tadashi G. Takaoka if (mId.isAlphabetKeyboard() && isShiftedOrShiftLocked() && !TextUtils.isEmpty(label) 2501ebedd7a15a8fd94e68fb43eb089ed87c4c5a480Tadashi G. Takaoka && label.length() < 3 && Character.isLowerCase(label.charAt(0))) { 251d773bf38a3c8f49ea56de67d3b828f8126f46ed2Tadashi G. Takaoka return label.toString().toUpperCase(mId.mLocale); 252d773bf38a3c8f49ea56de67d3b828f8126f46ed2Tadashi G. Takaoka } 253d773bf38a3c8f49ea56de67d3b828f8126f46ed2Tadashi G. Takaoka return label; 254571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 255571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 256ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka public static boolean isLetterCode(int code) { 2578cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka return code >= MINIMUM_LETTER_CODE; 258ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka } 259ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka 2604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Params { 2614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public KeyboardId mId; 2624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mThemeId; 2634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Total height and width of the keyboard, including the paddings and keys */ 2654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mOccupiedHeight; 2664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mOccupiedWidth; 2674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Base height and width of the keyboard used to calculate rows' or keys' heights and 2694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * widths 2704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 2714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBaseHeight; 2724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBaseWidth; 2734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mTopPadding; 2754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBottomPadding; 2764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalEdgesPadding; 2774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalCenterPadding; 2784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mDefaultRowHeight; 2804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mDefaultKeyWidth; 2814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalGap; 2824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mVerticalGap; 2834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public boolean mIsRtlKeyboard; 2854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMoreKeysTemplate; 2864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMaxMiniKeyboardColumn; 2874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int GRID_WIDTH; 2894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int GRID_HEIGHT; 2904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final Set<Key> mKeys = new HashSet<Key>(); 2924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final Set<Key> mShiftKeys = new HashSet<Key>(); 2934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final Set<Key> mShiftLockKeys = new HashSet<Key>(); 2944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); 2954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMostCommonKeyHeight = 0; 2974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMostCommonKeyWidth = 0; 2984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final TouchPositionCorrection mTouchPositionCorrection = 3004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka new TouchPositionCorrection(); 3014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class TouchPositionCorrection { 3034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3; 3044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public boolean mEnabled; 3064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mXs; 3074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mYs; 3084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mRadii; 3094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void load(String[] data) { 3114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int dataLength = data.length; 3124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) { 3134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) 3144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException( 3154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "the size of touch position correction data is invalid"); 3164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return; 3174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE; 3204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs = new float[length]; 3214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs = new float[length]; 3224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii = new float[length]; 3234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 3244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka for (int i = 0; i < dataLength; ++i) { 3254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE; 3264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE; 3274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final float value = Float.parseFloat(data[i]); 3284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (type == 0) { 3294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs[index] = value; 3304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (type == 1) { 3314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs[index] = value; 3324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 3334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii[index] = value; 3344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (NumberFormatException e) { 3374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) { 3384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException( 3394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "the number format for touch position correction data is invalid"); 3404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs = null; 3424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs = null; 3434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii = null; 3444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setEnabled(boolean enabled) { 3484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mEnabled = enabled; 3494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public boolean isValid() { 3524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mEnabled && mXs != null && mYs != null && mRadii != null 3534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0; 3544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected void clearKeys() { 3584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeys.clear(); 3594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mShiftKeys.clear(); 3604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mShiftLockKeys.clear(); 3614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka clearHistogram(); 3624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void onAddKey(Key key) { 3654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeys.add(key); 3664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka updateHistogram(key); 3674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (key.mCode == Keyboard.CODE_SHIFT) { 3684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mShiftKeys.add(key); 3694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (key.isSticky()) { 3704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mShiftLockKeys.add(key); 3714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mMaxHeightCount = 0; 3764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mMaxWidthCount = 0; 3774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>(); 3784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>(); 3794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void clearHistogram() { 3814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyHeight = 0; 3824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxHeightCount = 0; 3834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mHeightHistogram.clear(); 3844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxWidthCount = 0; 3864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyWidth = 0; 3874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mWidthHistogram.clear(); 3884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) { 3914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1; 3924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka histogram.put(key, count); 3934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return count; 3944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void updateHistogram(Key key) { 3974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Integer height = key.mHeight + key.mVerticalGap; 3984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int heightCount = updateHistogramCounter(mHeightHistogram, height); 3994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (heightCount > mMaxHeightCount) { 4004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxHeightCount = heightCount; 4014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyHeight = height; 4024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 4034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Integer width = key.mWidth + key.mHorizontalGap; 4054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthCount = updateHistogramCounter(mWidthHistogram, width); 4064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (widthCount > mMaxWidthCount) { 4074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxWidthCount = widthCount; 4084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyWidth = width; 4094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 4104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 4114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 4124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4135a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka /** 4140c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka * Returns the array of the keys that are closest to the given point. 4155a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * @param x the x-coordinate of the point 4165a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * @param y the y-coordinate of the point 4170c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka * @return the array of the nearest keys to the given point. If the given 4185a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * point is out of range, then an array of size zero is returned. 4195a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka */ 4200c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka public Key[] getNearestKeys(int x, int y) { 4214f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa // Avoid dead pixels at edges of the keyboard 4224f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1)); 4234f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1)); 4244f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa return mProximityInfo.getNearestKeys(adjustedX, adjustedY); 4255a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 42663584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka 4277dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka public static String printableCode(int code) { 4287dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka switch (code) { 4297dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SHIFT: return "shift"; 4307dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SWITCH_ALPHA_SYMBOL: return "symbol"; 4317dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_CAPSLOCK: return "capslock"; 4328cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka case CODE_OUTPUT_TEXT: return "text"; 4337dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_DELETE: return "delete"; 4347dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SHORTCUT: return "shortcut"; 4357dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_UNSPECIFIED: return "unspec"; 4367dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka default: 4372a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code <= 0) Log.w(TAG, "Unknown non-positive key code=" + code); 4382a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code < CODE_SPACE) return String.format("'\\u%02x'", code); 4392a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code < 0x100) return String.format("'%c'", code); 4402a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka return String.format("'\\u%04x'", code); 4417dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka } 4427dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka } 4434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4444087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka public static String toThemeName(int themeId) { 4454087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka // This should be aligned with theme-*.xml resource files' themeId attribute. 4464087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka switch (themeId) { 4474087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 0: return "Basic"; 4484087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 1: return "BasicHighContrast"; 4494087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 5: return "IceCreamSandwich"; 4504087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 6: return "Stone"; 4514087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 7: return "StoneBold"; 4524087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 8: return "GingerBread"; 4534087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka default: return null; 4544087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka } 4554087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka } 4564087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka 4574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** 4584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Keyboard Building helper. 4594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * 4604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * This class parses Keyboard XML file and eventually build a Keyboard. 4614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * The Keyboard XML file looks like: 4624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/keyboard.xml --< 4644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Keyboard keyboard_attributes*< 4654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Keyboard Content --< 4664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Row row_attributes*< 4674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Row Content --< 4684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Spacer horizontalGap="0.2in" /< 4704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >include keyboardLayout="@xml/other_keys"< 4714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Row< 4734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >include keyboardLayout="@xml/other_rows"< 4744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Keyboard< 4764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * The XML file which is included in other file must have >merge< as root element, 4784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * such as: 4794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/other_keys.xml --< 4814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >merge< 4824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/merge< 4854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * and 4874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/other_rows.xml --< 4894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >merge< 4904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Row row_attributes*< 4914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Row< 4934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/merge< 4954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * You can also use switch-case-default tags to select Rows and Keys. 4974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >switch< 4994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case case_attribute*< 5004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Any valid tags at switch position --< 5014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 5024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 5034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >default< 5044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Any valid tags at switch position --< 5054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/default< 5064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/switch< 5074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 5084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * You can declare Key style and specify styles within Key tags. 5094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 5104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >switch< 5114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case mode="email"< 5124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >key-style styleName="f1-key" parentStyle="modifier-key" 5134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * keyLabel=".com" 5144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * /< 5154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 5164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case mode="url"< 5174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >key-style styleName="f1-key" parentStyle="modifier-key" 5184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * keyLabel="http://" 5194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * /< 5204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 5214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/switch< 5224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 5234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key keyStyle="shift-key" ... /< 5244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 5254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 5264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Builder<KP extends Params> { 5284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG = Builder.class.getSimpleName(); 5294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final boolean DEBUG = false; 5304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Keyboard XML Tags 5324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_KEYBOARD = "Keyboard"; 5334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_ROW = "Row"; 5344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_KEY = "Key"; 5354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_SPACER = "Spacer"; 5364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_INCLUDE = "include"; 5374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_MERGE = "merge"; 5384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_SWITCH = "switch"; 5394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_CASE = "case"; 5404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_DEFAULT = "default"; 5414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static final String TAG_KEY_STYLE = "key-style"; 5424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int DEFAULT_KEYBOARD_COLUMNS = 10; 5444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int DEFAULT_KEYBOARD_ROWS = 4; 5454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final KP mParams; 5474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final Context mContext; 5484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final Resources mResources; 5494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final DisplayMetrics mDisplayMetrics; 5504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mCurrentY = 0; 5524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Row mCurrentRow = null; 5534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean mLeftEdge; 5544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean mTopEdge; 5554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Key mRightEdgeKey = null; 5564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final KeyStyles mKeyStyles = new KeyStyles(); 5574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** 5594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. 5604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Some of the key size defaults can be overridden per row from what the {@link Keyboard} 5614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * defines. 5624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 5634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Row { 5644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyWidth enum constants 5654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_NOT_ENUM = 0; 5664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_FILL_RIGHT = -1; 5674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_FILL_BOTH = -2; 5684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Params mParams; 5704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Default width of a key in this row. */ 5714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final float mDefaultKeyWidth; 5724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Default height of a key in this row. */ 5734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final int mRowHeight; 5744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final int mCurrentY; 5764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Will be updated by {@link Key}'s constructor. 5774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private float mCurrentX; 5784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Row(Resources res, Params params, XmlPullParser parser, int y) { 5804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams = params; 5814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 5824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard); 5834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRowHeight = (int)Builder.getDimensionOrFraction(keyboardAttr, 5844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_rowHeight, 5854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight, params.mDefaultRowHeight); 5864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardAttr.recycle(); 5874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 5884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 5894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mDefaultKeyWidth = Builder.getDimensionOrFraction(keyAttr, 5904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, 5914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth, params.mDefaultKeyWidth); 5924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttr.recycle(); 5934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY = y; 5954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX = 0.0f; 5964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setXPos(float keyXPos) { 5994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX = keyXPos; 6004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void advanceXPos(float width) { 6034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX += width; 6044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int getKeyY() { 6074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentY; 6084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float getKeyX(TypedArray keyAttr) { 6114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthType = Builder.getEnumValue(keyAttr, 6124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 6134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (widthType == KEYWIDTH_FILL_BOTH) { 6144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillBoth, the key width should start right after the nearest 6154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // key on the left hand side. 6164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentX; 6174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardRightEdge = mParams.mOccupiedWidth 6204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - mParams.mHorizontalEdgesPadding; 6214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { 6224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final float keyXPos = Builder.getDimensionOrFraction(keyAttr, 6234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0); 6244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (keyXPos < 0) { 6254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyXPos is negative, the actual x-coordinate will be 6264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyboardWidth + keyXPos. 6274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyXPos shouldn't be less than mCurrentX because drawable area for this 6284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // key starts at mCurrentX. Or, this key will overlaps the adjacent key on 6294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // its left hand side. 6304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return Math.max(keyXPos + keyboardRightEdge, mCurrentX); 6314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 6324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return keyXPos + mParams.mHorizontalEdgesPadding; 6334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentX; 6364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float getKeyWidth(TypedArray keyAttr, float keyXPos) { 6394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthType = Builder.getEnumValue(keyAttr, 6404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 6414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka switch (widthType) { 6424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka case KEYWIDTH_FILL_RIGHT: 6434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka case KEYWIDTH_FILL_BOTH: 6444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardRightEdge = 6454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding; 6464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillRight, the actual key width will be determined to fill 6474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // out the area up to the right edge of the keyboard. 6484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillBoth, the actual key width will be determined to fill out 6494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the area between the nearest key on the left hand side and the right edge of 6504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the keyboard. 6514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return keyboardRightEdge - keyXPos; 6524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka default: // KEYWIDTH_NOT_ENUM 6534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return Builder.getDimensionOrFraction(keyAttr, 6544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, 6554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mBaseWidth, mDefaultKeyWidth); 6564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Builder(Context context, KP params) { 6614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mContext = context; 6624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Resources res = context.getResources(); 6634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mResources = res; 6644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mDisplayMetrics = res.getDisplayMetrics(); 6654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams = params; 6674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka setTouchPositionCorrectionData(context, params); 6694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); 6714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); 6724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static void setTouchPositionCorrectionData(Context context, Params params) { 6754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 6764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka null, R.styleable.Keyboard, R.attr.keyboardStyle, 0); 6774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0); 6784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int resourceId = a.getResourceId( 6794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_touchPositionCorrectionData, 0); 6804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 6814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (resourceId == 0) { 6824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) 6831e4684ad24914cde713980bb4174810bbf8bae10Jean Chalard Log.e(TAG, "touchPositionCorrectionData is not defined"); 6844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return; 6854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String[] data = context.getResources().getStringArray(resourceId); 6884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mTouchPositionCorrection.load(data); 6894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Builder<KP> load(int xmlId, KeyboardId id) { 6924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mId = id; 6934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final XmlResourceParser parser = mResources.getXml(xmlId); 6944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 6954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboard(parser); 6964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (XmlPullParserException e) { 6974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Log.w(TAG, "keyboard XML parse error: " + e); 6984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new IllegalArgumentException(e); 6994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (IOException e) { 7004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Log.w(TAG, "keyboard XML parse error: " + e); 7014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException(e); 7024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 7034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parser.close(); 7044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return this; 7064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setTouchPositionCorrectionEnabled(boolean enabled) { 7094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mTouchPositionCorrection.setEnabled(enabled); 7104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Keyboard build() { 7134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return new Keyboard(mParams); 7144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboard(XmlPullParser parser) 7174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 7184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mParams.mId)); 7194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 7204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 7214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 7224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 7234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEYBOARD.equals(tag)) { 7244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardAttributes(parser); 7254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka startKeyboard(); 7264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, false); 7274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 7284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 7294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD); 7304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboardAttributes(XmlPullParser parser) { 7364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int displayWidth = mDisplayMetrics.widthPixels; 7374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray keyboardAttr = mContext.obtainStyledAttributes( 7384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle, 7394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.style.Keyboard); 7404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), 7414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 7424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 7434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int displayHeight = mDisplayMetrics.heightPixels; 7444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardHeight = (int)keyboardAttr.getDimension( 7454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardHeight, displayHeight / 2); 7464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, 7474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); 7484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, 7494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2); 7504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (minKeyboardHeight < 0) { 7514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Specified fraction was negative, so it should be calculated against display 7524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // width. 7534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr, 7544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2); 7554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Params params = mParams; 7574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Keyboard height will not exceed maxKeyboardHeight and will not be less than 7584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // minKeyboardHeight. 7594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mOccupiedHeight = Math.max( 7604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); 7614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mOccupiedWidth = params.mId.mWidth; 7624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr, 7634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0); 7644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr, 7654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0); 7664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr, 7674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardHorizontalEdgesPadding, 7684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mOccupiedWidth, 0); 7694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2 7714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - params.mHorizontalCenterPadding; 7724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr, 7734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, 7744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS); 7754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr, 7764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0); 7774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr, 7784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0); 7794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding 7804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - params.mBottomPadding + params.mVerticalGap; 7814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr, 7824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_rowHeight, params.mBaseHeight, 7834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight / DEFAULT_KEYBOARD_ROWS); 7844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mIsRtlKeyboard = keyboardAttr.getBoolean( 7864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_isRtlKeyboard, false); 7874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mMoreKeysTemplate = keyboardAttr.getResourceId( 7884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_moreKeysTemplate, 0); 7894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mMaxMiniKeyboardColumn = keyAttr.getInt( 7904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_maxMoreKeysColumn, 5); 7914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mIconsSet.loadIcons(keyboardAttr); 7934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 7944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttr.recycle(); 7954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardAttr.recycle(); 7964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboardContent(XmlPullParser parser, boolean skip) 8004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 8024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 8034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 8044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_ROW.equals(tag)) { 8064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Row row = parseRowAttributes(parser); 8074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW)); 8084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!skip) 8094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka startRow(row); 8104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 8114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_INCLUDE.equals(tag)) { 8124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeKeyboardContent(parser, skip); 8134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SWITCH.equals(tag)) { 8144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchKeyboardContent(parser, skip); 8154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyStyle(parser, skip); 8174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW); 8194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 8214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEYBOARD.equals(tag)) { 8234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKeyboard(); 8244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) 8264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || TAG_MERGE.equals(tag)) { 8274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("</%s>", tag)); 8284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka continue; 8314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW); 8334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException { 8394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 8404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard); 8414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 8424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (a.hasValue(R.styleable.Keyboard_horizontalGap)) 8434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap"); 8444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (a.hasValue(R.styleable.Keyboard_verticalGap)) 8454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap"); 8464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return new Row(mResources, mParams, parser, mCurrentY); 8474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 8484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 8494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseRowContent(XmlPullParser parser, Row row, boolean skip) 8534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 8554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 8564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 8574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEY.equals(tag)) { 8594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKey(parser, row, skip); 8604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SPACER.equals(tag)) { 8614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSpacer(parser, row, skip); 8624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_INCLUDE.equals(tag)) { 8634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeRowContent(parser, row, skip); 8644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SWITCH.equals(tag)) { 8654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchRowContent(parser, row, skip); 8664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyStyle(parser, skip); 8684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); 8704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 8724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_ROW.equals(tag)) { 8744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_ROW)); 8754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!skip) 8764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endRow(row); 8774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) 8794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || TAG_MERGE.equals(tag)) { 8804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("</%s>", tag)); 8814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka continue; 8844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); 8864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKey(XmlPullParser parser, Row row, boolean skip) 8924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 8944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY, parser); 8954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Key key = new Key(mResources, mParams, row, parser, mKeyStyles); 8974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />", 8984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode, 8994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Arrays.toString(key.mMoreKeys))); 9004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY, parser); 9014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKey(key); 9024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSpacer(XmlPullParser parser, Row row, boolean skip) 9064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 9084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_SPACER, parser); 9094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Key.Spacer spacer = new Key.Spacer( 9114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mResources, mParams, row, parser, mKeyStyles); 9124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER)); 9134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_SPACER, parser); 9144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKey(spacer); 9154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip) 9194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeInternal(parser, null, skip); 9214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip) 9244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeInternal(parser, row, skip); 9264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip) 9294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 9314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); 9324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 9344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include); 9354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int keyboardLayout = 0; 9364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 9374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkAttributeExists(a, 9384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout", 9394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TAG_INCLUDE, parser); 9404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardLayout = a.getResourceId( 9414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include_keyboardLayout, 0); 9424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 9434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 9444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); 9474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />", 9484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout))); 9494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout); 9504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 9514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseMerge(parserForInclude, row, skip); 9524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 9534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parserForInclude.close(); 9544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseMerge(XmlPullParser parser, Row row, boolean skip) 9594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 9614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 9624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 9634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 9644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_MERGE.equals(tag)) { 9654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 9664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, skip); 9674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 9694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 9714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.ParseException( 9734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "Included keyboard layout must have <merge> root element", parser); 9744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip) 9804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchInternal(parser, null, skip); 9824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip) 9854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchInternal(parser, row, skip); 9874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip) 9904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mParams.mId)); 9924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka boolean selected = false; 9934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 9944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 9954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 9964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 9974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_CASE.equals(tag)) { 9984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka selected |= parseCase(parser, row, selected ? true : skip); 9994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_DEFAULT.equals(tag)) { 10004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka selected |= parseDefault(parser, row, selected ? true : skip); 10014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); 10034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 10054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 10064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_SWITCH.equals(tag)) { 10074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_SWITCH)); 10084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 10094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); 10114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseCase(XmlPullParser parser, Row row, boolean skip) 10174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean selected = parseCaseCondition(parser); 10194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 10204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Processing Rows. 10214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, selected ? skip : true); 10224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Processing Keys. 10244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, selected ? skip : true); 10254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return selected; 10274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseCaseCondition(XmlPullParser parser) { 10304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final KeyboardId id = mParams.mId; 10314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (id == null) 10324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 10334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 10354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case); 10364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 10374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean modeMatched = matchTypedValue(a, 10384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode)); 10394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean navigateActionMatched = matchBoolean(a, 10404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_navigateAction, id.navigateAction()); 10414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean passwordInputMatched = matchBoolean(a, 10424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_passwordInput, id.passwordInput()); 10434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean hasSettingsKeyMatched = matchBoolean(a, 10444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_hasSettingsKey, id.hasSettingsKey()); 10454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean f2KeyModeMatched = matchInteger(a, 10464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_f2KeyMode, id.f2KeyMode()); 10474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean clobberSettingsKeyMatched = matchBoolean(a, 10484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey); 10494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean shortcutKeyEnabledMatched = matchBoolean(a, 10504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); 10514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean hasShortcutKeyMatched = matchBoolean(a, 10524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); 10534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // As noted at {@link KeyboardId} class, we are interested only in enum value 10544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // masked by {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and 10554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching 10564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // this attribute with id.mImeOptions as integer value is enough for our purpose. 10574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean imeActionMatched = matchInteger(a, 10584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_imeAction, id.imeAction()); 10594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean localeCodeMatched = matchString(a, 10604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_localeCode, id.mLocale.toString()); 10614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean languageCodeMatched = matchString(a, 10624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage()); 10634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean countryCodeMatched = matchString(a, 10644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry()); 10654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean selected = modeMatched && navigateActionMatched 10664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka && passwordInputMatched && hasSettingsKeyMatched && f2KeyModeMatched 10674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka && clobberSettingsKeyMatched && shortcutKeyEnabledMatched 10684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka && hasShortcutKeyMatched && imeActionMatched && localeCodeMatched 10694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka && languageCodeMatched && countryCodeMatched; 10704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE, 10724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), 10734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"), 10744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"), 10754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"), 10764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(KeyboardId.f2KeyModeName( 10774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), "f2KeyMode"), 10784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey, 10794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "clobberSettingsKey"), 10804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled, 10814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "shortcutKeyEnabled"), 10824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"), 10834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(EditorInfoCompatUtils.imeOptionsName( 10844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"), 10854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), "localeCode"), 10864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), 10874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "languageCode"), 10884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"), 10894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Boolean.toString(selected))); 10904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return selected; 10924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 10934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 10944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchInteger(TypedArray a, int index, int value) { 10984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 10994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) || a.getInt(index, 0) == value; 11014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchBoolean(TypedArray a, int index, boolean value) { 11044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) || a.getBoolean(index, false) == value; 11074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchString(TypedArray a, int index, String value) { 11104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) 11134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || stringArrayContains(a.getString(index).split("\\|"), value); 11144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchTypedValue(TypedArray a, int index, int intValue, 11174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka String strValue) { 11184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue v = a.peekValue(index); 11214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (v == null) 11224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isIntegerValue(v)) { 11254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return intValue == a.getInt(index, 0); 11264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (isStringValue(v)) { 11274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return stringArrayContains(a.getString(index).split("\\|"), strValue); 11284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return false; 11304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean stringArrayContains(String[] array, String value) { 11334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka for (final String elem : array) { 11344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (elem.equals(value)) 11354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return false; 11384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseDefault(XmlPullParser parser, Row row, boolean skip) 11414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 11424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT)); 11434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 11444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, skip); 11454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 11464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 11474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyStyle(XmlPullParser parser, boolean skip) 11524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException { 11534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), 11544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_KeyStyle); 11554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), 11564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 11574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 11584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) 11594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE 11604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka + "/> needs styleName attribute", parser); 11614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!skip) 11624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); 11634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 11644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyStyleAttr.recycle(); 11654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttrs.recycle(); 11664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void startKeyboard() { 11704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY += mParams.mTopPadding; 11714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mTopEdge = true; 11724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void startRow(Row row) { 11754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka addEdgeSpace(mParams.mHorizontalEdgesPadding, row); 11764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentRow = row; 11774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = true; 11784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 11794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endRow(Row row) { 11824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mCurrentRow == null) 11834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new InflateException("orphant end row tag"); 11844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mRightEdgeKey != null) { 11854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey.markAsRightEdge(mParams); 11864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 11874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka addEdgeSpace(mParams.mHorizontalEdgesPadding, row); 11894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY += row.mRowHeight; 11904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentRow = null; 11914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mTopEdge = false; 11924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endKey(Key key) { 11954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.onAddKey(key); 11964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mLeftEdge) { 11974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka key.markAsLeftEdge(mParams); 11984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = false; 11994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mTopEdge) { 12014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka key.markAsTopEdge(mParams); 12024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = key; 12044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endKeyboard() { 12074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // nothing to do here. 12084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void addEdgeSpace(float width, Row row) { 12114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka row.advanceXPos(width); 12124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = false; 12134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 12144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static float getDimensionOrFraction(TypedArray a, int index, int base, 12174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka float defValue) { 12184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue value = a.peekValue(index); 12194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (value == null) 12204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isFractionValue(value)) { 12224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getFraction(index, base, base, defValue); 12234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (isDimensionValue(value)) { 12244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getDimension(index, defValue); 12254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static int getEnumValue(TypedArray a, int index, int defValue) { 12304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue value = a.peekValue(index); 12314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (value == null) 12324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isIntegerValue(value)) { 12344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getInt(index, defValue); 12354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isFractionValue(TypedValue v) { 12404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_FRACTION; 12414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isDimensionValue(TypedValue v) { 12444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_DIMENSION; 12454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isIntegerValue(TypedValue v) { 12484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; 12494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isStringValue(TypedValue v) { 12524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_STRING; 12534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static String textAttr(String value, String name) { 12564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return value != null ? String.format(" %s=%s", name, value) : ""; 12574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static String booleanAttr(TypedArray a, int index, String name) { 12604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.hasValue(index) 12614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka ? String.format(" %s=%s", name, a.getBoolean(index, false)) : ""; 12624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12645a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka} 1265