Keyboard.java revision e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476c
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; 23e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatokimport android.text.TextUtils; 24a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaokaimport android.util.AttributeSet; 254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.util.DisplayMetrics; 267dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaokaimport android.util.Log; 274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.util.TypedValue; 284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.util.Xml; 294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport android.view.InflateException; 305a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.compat.EditorInfoCompatUtils; 324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyStyles; 33c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 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; 42e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatokimport java.util.ArrayList; 434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport java.util.Arrays; 448da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaokaimport java.util.Collections; 452013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaokaimport java.util.HashMap; 464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport java.util.HashSet; 47e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatokimport java.util.List; 48167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaokaimport java.util.Map; 49167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaokaimport java.util.Set; 505a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 515a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka/** 525a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard 535a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * consists of rows of keys. 545a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p> 555a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <pre> 565a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Keyboard 575a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:keyWidth="%10p" 585a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:keyHeight="50px" 595a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:horizontalGap="2px" 605a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:verticalGap="2px" > 615a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Row latin:keyWidth="32px" > 625a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Key latin:keyLabel="A" /> 635a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * ... 645a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </Row> 655a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * ... 665a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </Keyboard> 675a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </pre> 685a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka */ 695a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapublic class Keyboard { 707dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka private static final String TAG = Keyboard.class.getSimpleName(); 717dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka 72ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka /** Some common keys code. Must be positive. 73ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka * These should be aligned with values/keycodes.xml 74ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka */ 75571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_ENTER = '\n'; 76571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_TAB = '\t'; 77571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_SPACE = ' '; 78571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_PERIOD = '.'; 790730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_DASH = '-'; 800730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_SINGLE_QUOTE = '\''; 810730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_DOUBLE_QUOTE = '"'; 822b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // TODO: Check how this should work for right-to-left languages. It seems to stand 832b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // that for rtl languages, a closing parenthesis is a left parenthesis. Is this 842b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // managed by the font? Or is it a different char? 852b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_PARENTHESIS = ')'; 862b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_SQUARE_BRACKET = ']'; 872b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_CURLY_BRACKET = '}'; 882b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_ANGLE_BRACKET = '>'; 89851c3267d4ab21f892b4164783bb4959c88b44ffTadashi G. Takaoka public static final int CODE_DIGIT0 = '0'; 90851c3267d4ab21f892b4164783bb4959c88b44ffTadashi G. Takaoka public static final int CODE_PLUS = '+'; 918cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka private static final int MINIMUM_LETTER_CODE = CODE_TAB; 922b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard 938cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka /** Special keys code. Must be negative. 94ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka * These should be aligned with values/keycodes.xml 95ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka */ 96571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_SHIFT = -1; 97e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka public static final int CODE_SWITCH_ALPHA_SYMBOL = -2; 988cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka public static final int CODE_OUTPUT_TEXT = -4; 99571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_DELETE = -5; 100d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka public static final int CODE_SETTINGS = -6; 101cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public static final int CODE_SHORTCUT = -7; 102c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka // Code value representing the code is not specified. 1038cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka public static final int CODE_UNSPECIFIED = -9; 1045a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 105167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka public final KeyboardId mId; 10663584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka public final int mThemeId; 107167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka 108167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka /** Total height of the keyboard, including the padding and keys */ 1098da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mOccupiedHeight; 1108da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka /** Total width of the keyboard, including the padding and keys */ 1118da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mOccupiedWidth; 112167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka 1138fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka /** The padding above the keyboard */ 1148fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka public final int mTopPadding; 1155a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka /** Default gap between rows */ 1168da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mVerticalGap; 1178da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1188fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka public final int mMostCommonKeyHeight; 1198da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mMostCommonKeyWidth; 1205a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1219d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka /** More keys keyboard template */ 1229d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public final int mMoreKeysTemplate; 1239b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka 1249237a72634be821c22911633ef0848130e162d58Tadashi G. Takaoka /** Maximum column for mini keyboard */ 1259237a72634be821c22911633ef0848130e162d58Tadashi G. Takaoka public final int mMaxMiniKeyboardColumn; 1269b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka 1278da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka /** List of keys and icons in this keyboard */ 1284a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka public final Set<Key> mKeys; 1294a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka public final Set<Key> mShiftKeys; 1308da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final KeyboardIconsSet mIconsSet; 1316fb97bf71cee2a0775410a05478ed6a667aa847fTadashi G. Takaoka 1322013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>(); 133c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 1348fbd55229243cb66c03d5ea1f79dfb39f596590dsatok private final ProximityInfo mProximityInfo; 1358fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 136e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok public final Map<Integer, List<Integer>> mAdditionalProximityChars; 137e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok 1384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Keyboard(Params params) { 1398da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mId = params.mId; 14063584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka mThemeId = params.mThemeId; 1418da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mOccupiedHeight = params.mOccupiedHeight; 1428da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mOccupiedWidth = params.mOccupiedWidth; 1438fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka mMostCommonKeyHeight = params.mMostCommonKeyHeight; 1448da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mMostCommonKeyWidth = params.mMostCommonKeyWidth; 1459d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysTemplate = params.mMoreKeysTemplate; 1469237a72634be821c22911633ef0848130e162d58Tadashi G. Takaoka mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn; 1478da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1488fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka mTopPadding = params.mTopPadding; 1498da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mVerticalGap = params.mVerticalGap; 1508da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1514a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka mKeys = Collections.unmodifiableSet(params.mKeys); 1524a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys); 1538da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mIconsSet = params.mIconsSet; 154e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok mAdditionalProximityChars = params.mAdditionalProximityChars; 1555a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1560d5494c66ac3e5947040e8148091163a1c8716f7satok mProximityInfo = new ProximityInfo( 1578da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, 158e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection, 159e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok params.mAdditionalProximityChars); 1608fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1618fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 162043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard public ProximityInfo getProximityInfo() { 163043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard return mProximityInfo; 1645a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 1655a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1662013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka public Key getKey(int code) { 1678cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka if (code == CODE_UNSPECIFIED) { 168623d0155b6a316fdc9335370cdd4005bbb474ef3Tadashi G. Takaoka return null; 169623d0155b6a316fdc9335370cdd4005bbb474ef3Tadashi G. Takaoka } 1702013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka final Integer keyCode = code; 1712013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (mKeyCache.containsKey(keyCode)) { 1722013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return mKeyCache.get(keyCode); 1732013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1742013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 1752013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka for (final Key key : mKeys) { 1762013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (key.mCode == code) { 1772013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka mKeyCache.put(keyCode, key); 1782013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return key; 1792013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1802013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1812013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka mKeyCache.put(keyCode, null); 1822013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return null; 1832013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1842013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 185c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method. 186571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public boolean isShiftLocked() { 187ca2f051cc173acc3bce384ebfe08068564bc8e07Tadashi G. Takaoka return mId.isAlphabetShiftLockedKeyboard(); 18807145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka } 18907145a3706d7692806b9c53548795fa2dbf8f4f0Tadashi G. Takaoka 190c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method. 1915a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka public boolean isShiftedOrShiftLocked() { 192ca2f051cc173acc3bce384ebfe08068564bc8e07Tadashi G. Takaoka return mId.isAlphabetShiftedOrShiftLockedKeyboard(); 193571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 194571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 195c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method. 196ca2f051cc173acc3bce384ebfe08068564bc8e07Tadashi G. Takaoka public boolean isManualShifted() { 197ca2f051cc173acc3bce384ebfe08068564bc8e07Tadashi G. Takaoka return mId.isAlphabetManualShiftedKeyboard(); 198571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 199571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 200ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka public static boolean isLetterCode(int code) { 2018cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka return code >= MINIMUM_LETTER_CODE; 202ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka } 203ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka 2044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Params { 2054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public KeyboardId mId; 2064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mThemeId; 2074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Total height and width of the keyboard, including the paddings and keys */ 2094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mOccupiedHeight; 2104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mOccupiedWidth; 2114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Base height and width of the keyboard used to calculate rows' or keys' heights and 2134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * widths 2144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 2154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBaseHeight; 2164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBaseWidth; 2174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mTopPadding; 2194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBottomPadding; 2204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalEdgesPadding; 2214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalCenterPadding; 2224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mDefaultRowHeight; 2244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mDefaultKeyWidth; 2254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalGap; 2264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mVerticalGap; 2274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMoreKeysTemplate; 2294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMaxMiniKeyboardColumn; 2304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int GRID_WIDTH; 2324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int GRID_HEIGHT; 2334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final Set<Key> mKeys = new HashSet<Key>(); 2354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final Set<Key> mShiftKeys = new HashSet<Key>(); 2364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); 237e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok // TODO: Should be in Key instead of Keyboard.Params? 238e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok public final Map<Integer, List<Integer>> mAdditionalProximityChars = 239e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok new HashMap<Integer, List<Integer>>(); 2404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 24109f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka public KeyboardSet.KeysCache mKeysCache; 24209f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka 2434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMostCommonKeyHeight = 0; 2444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMostCommonKeyWidth = 0; 2454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final TouchPositionCorrection mTouchPositionCorrection = 2474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka new TouchPositionCorrection(); 2484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class TouchPositionCorrection { 2504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3; 2514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public boolean mEnabled; 2534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mXs; 2544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mYs; 2554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mRadii; 2564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void load(String[] data) { 2584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int dataLength = data.length; 2594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) { 2604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) 2614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException( 2624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "the size of touch position correction data is invalid"); 2634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return; 2644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE; 2674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs = new float[length]; 2684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs = new float[length]; 2694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii = new float[length]; 2704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 2714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka for (int i = 0; i < dataLength; ++i) { 2724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE; 2734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE; 2744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final float value = Float.parseFloat(data[i]); 2754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (type == 0) { 2764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs[index] = value; 2774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (type == 1) { 2784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs[index] = value; 2794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 2804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii[index] = value; 2814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (NumberFormatException e) { 2844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) { 2854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException( 2864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "the number format for touch position correction data is invalid"); 2874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs = null; 2894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs = null; 2904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii = null; 2914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setEnabled(boolean enabled) { 2954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mEnabled = enabled; 2964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public boolean isValid() { 2994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mEnabled && mXs != null && mYs != null && mRadii != null 3004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0; 3014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected void clearKeys() { 3054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeys.clear(); 3064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mShiftKeys.clear(); 3074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka clearHistogram(); 3084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 31009f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka public void onAddKey(Key newKey) { 31109f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka final Key key = (mKeysCache != null) ? mKeysCache.get(newKey) : newKey; 3124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeys.add(key); 3134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka updateHistogram(key); 3144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (key.mCode == Keyboard.CODE_SHIFT) { 3154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mShiftKeys.add(key); 3164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mMaxHeightCount = 0; 3204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mMaxWidthCount = 0; 3214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>(); 3224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>(); 3234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void clearHistogram() { 3254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyHeight = 0; 3264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxHeightCount = 0; 3274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mHeightHistogram.clear(); 3284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxWidthCount = 0; 3304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyWidth = 0; 3314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mWidthHistogram.clear(); 3324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) { 3354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1; 3364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka histogram.put(key, count); 3374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return count; 3384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void updateHistogram(Key key) { 3414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Integer height = key.mHeight + key.mVerticalGap; 3424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int heightCount = updateHistogramCounter(mHeightHistogram, height); 3434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (heightCount > mMaxHeightCount) { 3444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxHeightCount = heightCount; 3454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyHeight = height; 3464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Integer width = key.mWidth + key.mHorizontalGap; 3494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthCount = updateHistogramCounter(mWidthHistogram, width); 3504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (widthCount > mMaxWidthCount) { 3514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxWidthCount = widthCount; 3524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyWidth = width; 3534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3575a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka /** 3580c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka * Returns the array of the keys that are closest to the given point. 3595a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * @param x the x-coordinate of the point 3605a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * @param y the y-coordinate of the point 3610c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka * @return the array of the nearest keys to the given point. If the given 3625a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * point is out of range, then an array of size zero is returned. 3635a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka */ 3640c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka public Key[] getNearestKeys(int x, int y) { 3654f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa // Avoid dead pixels at edges of the keyboard 3664f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1)); 3674f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1)); 3684f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa return mProximityInfo.getNearestKeys(adjustedX, adjustedY); 3695a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 37063584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka 371e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok public Map<Integer, List<Integer>> getAdditionalProximityChars() { 372e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok return mAdditionalProximityChars; 373e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 374e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok 3757dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka public static String printableCode(int code) { 3767dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka switch (code) { 3777dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SHIFT: return "shift"; 3787dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SWITCH_ALPHA_SYMBOL: return "symbol"; 3798cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka case CODE_OUTPUT_TEXT: return "text"; 3807dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_DELETE: return "delete"; 381a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka case CODE_SETTINGS: return "settings"; 3827dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SHORTCUT: return "shortcut"; 3837dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_UNSPECIFIED: return "unspec"; 384ca2f051cc173acc3bce384ebfe08068564bc8e07Tadashi G. Takaoka case CODE_TAB: return "tab"; 385ca2f051cc173acc3bce384ebfe08068564bc8e07Tadashi G. Takaoka case CODE_ENTER: return "enter"; 3867dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka default: 3872a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code <= 0) Log.w(TAG, "Unknown non-positive key code=" + code); 3882a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code < CODE_SPACE) return String.format("'\\u%02x'", code); 3892a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code < 0x100) return String.format("'%c'", code); 3902a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka return String.format("'\\u%04x'", code); 3917dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka } 3927dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka } 3934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3944087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka public static String toThemeName(int themeId) { 3954087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka // This should be aligned with theme-*.xml resource files' themeId attribute. 3964087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka switch (themeId) { 3974087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 0: return "Basic"; 3984087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 1: return "BasicHighContrast"; 3994087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 5: return "IceCreamSandwich"; 4004087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 6: return "Stone"; 4014087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 7: return "StoneBold"; 4024087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 8: return "GingerBread"; 4034087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka default: return null; 4044087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka } 4054087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka } 4064087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka 4074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** 4084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Keyboard Building helper. 4094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * 4104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * This class parses Keyboard XML file and eventually build a Keyboard. 4114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * The Keyboard XML file looks like: 4124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/keyboard.xml --< 4144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Keyboard keyboard_attributes*< 4154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Keyboard Content --< 4164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Row row_attributes*< 4174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Row Content --< 4184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Spacer horizontalGap="0.2in" /< 4204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >include keyboardLayout="@xml/other_keys"< 4214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Row< 4234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >include keyboardLayout="@xml/other_rows"< 4244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Keyboard< 4264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * The XML file which is included in other file must have >merge< as root element, 4284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * such as: 4294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/other_keys.xml --< 4314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >merge< 4324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/merge< 4354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * and 4374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/other_rows.xml --< 4394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >merge< 4404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Row row_attributes*< 4414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Row< 4434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/merge< 4454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * You can also use switch-case-default tags to select Rows and Keys. 4474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >switch< 4494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case case_attribute*< 4504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Any valid tags at switch position --< 4514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >default< 4544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Any valid tags at switch position --< 4554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/default< 4564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/switch< 4574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * You can declare Key style and specify styles within Key tags. 4594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >switch< 4614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case mode="email"< 4624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >key-style styleName="f1-key" parentStyle="modifier-key" 4634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * keyLabel=".com" 4644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * /< 4654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case mode="url"< 4674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >key-style styleName="f1-key" parentStyle="modifier-key" 4684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * keyLabel="http://" 4694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * /< 4704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/switch< 4724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key keyStyle="shift-key" ... /< 4744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 4764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Builder<KP extends Params> { 4784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG = Builder.class.getSimpleName(); 4794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final boolean DEBUG = false; 4804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Keyboard XML Tags 4824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_KEYBOARD = "Keyboard"; 4834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_ROW = "Row"; 4844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_KEY = "Key"; 4854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_SPACER = "Spacer"; 4864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_INCLUDE = "include"; 4874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_MERGE = "merge"; 4884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_SWITCH = "switch"; 4894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_CASE = "case"; 4904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_DEFAULT = "default"; 4914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static final String TAG_KEY_STYLE = "key-style"; 4924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int DEFAULT_KEYBOARD_COLUMNS = 10; 4944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int DEFAULT_KEYBOARD_ROWS = 4; 4954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final KP mParams; 4974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final Context mContext; 4984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final Resources mResources; 4994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final DisplayMetrics mDisplayMetrics; 5004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mCurrentY = 0; 5024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Row mCurrentRow = null; 5034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean mLeftEdge; 5044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean mTopEdge; 5054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Key mRightEdgeKey = null; 5064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final KeyStyles mKeyStyles = new KeyStyles(); 5074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** 5094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. 5104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Some of the key size defaults can be overridden per row from what the {@link Keyboard} 5114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * defines. 5124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 5134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Row { 5144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyWidth enum constants 5154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_NOT_ENUM = 0; 5164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_FILL_RIGHT = -1; 5174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_FILL_BOTH = -2; 5184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Params mParams; 5204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Default width of a key in this row. */ 521a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka private float mDefaultKeyWidth; 5224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Default height of a key in this row. */ 5234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final int mRowHeight; 5244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final int mCurrentY; 5264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Will be updated by {@link Key}'s constructor. 5274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private float mCurrentX; 5284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Row(Resources res, Params params, XmlPullParser parser, int y) { 5304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams = params; 5314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 5324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard); 5334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRowHeight = (int)Builder.getDimensionOrFraction(keyboardAttr, 5344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_rowHeight, 5354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight, params.mDefaultRowHeight); 5364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardAttr.recycle(); 5374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 5384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 5394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mDefaultKeyWidth = Builder.getDimensionOrFraction(keyAttr, 5404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, 5414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth, params.mDefaultKeyWidth); 5424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttr.recycle(); 5434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY = y; 5454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX = 0.0f; 5464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 548a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public float getDefaultKeyWidth() { 549a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka return mDefaultKeyWidth; 550a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 551a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 552a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public void setDefaultKeyWidth(float defaultKeyWidth) { 553a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka mDefaultKeyWidth = defaultKeyWidth; 554a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 555a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 5564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setXPos(float keyXPos) { 5574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX = keyXPos; 5584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void advanceXPos(float width) { 5614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX += width; 5624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int getKeyY() { 5654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentY; 5664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float getKeyX(TypedArray keyAttr) { 5694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthType = Builder.getEnumValue(keyAttr, 5704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 5714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (widthType == KEYWIDTH_FILL_BOTH) { 5724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillBoth, the key width should start right after the nearest 5734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // key on the left hand side. 5744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentX; 5754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardRightEdge = mParams.mOccupiedWidth 5784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - mParams.mHorizontalEdgesPadding; 5794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { 5804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final float keyXPos = Builder.getDimensionOrFraction(keyAttr, 5814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0); 5824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (keyXPos < 0) { 5834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyXPos is negative, the actual x-coordinate will be 5844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyboardWidth + keyXPos. 5854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyXPos shouldn't be less than mCurrentX because drawable area for this 5864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // key starts at mCurrentX. Or, this key will overlaps the adjacent key on 5874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // its left hand side. 5884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return Math.max(keyXPos + keyboardRightEdge, mCurrentX); 5894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 5904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return keyXPos + mParams.mHorizontalEdgesPadding; 5914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentX; 5944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 596a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public float getKeyWidth(TypedArray keyAttr) { 597a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka return getKeyWidth(keyAttr, mCurrentX); 598a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 599a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 6004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float getKeyWidth(TypedArray keyAttr, float keyXPos) { 6014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthType = Builder.getEnumValue(keyAttr, 6024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 6034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka switch (widthType) { 6044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka case KEYWIDTH_FILL_RIGHT: 6054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka case KEYWIDTH_FILL_BOTH: 6064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardRightEdge = 6074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding; 6084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillRight, the actual key width will be determined to fill 6094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // out the area up to the right edge of the keyboard. 6104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillBoth, the actual key width will be determined to fill out 6114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the area between the nearest key on the left hand side and the right edge of 6124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the keyboard. 6134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return keyboardRightEdge - keyXPos; 6144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka default: // KEYWIDTH_NOT_ENUM 6154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return Builder.getDimensionOrFraction(keyAttr, 6164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, 6174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mBaseWidth, mDefaultKeyWidth); 6184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Builder(Context context, KP params) { 6234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mContext = context; 6244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Resources res = context.getResources(); 6254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mResources = res; 6264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mDisplayMetrics = res.getDisplayMetrics(); 6274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams = params; 6294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka setTouchPositionCorrectionData(context, params); 631e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok setAdditionalProximityChars(context, params); 6324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); 6344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); 6354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static void setTouchPositionCorrectionData(Context context, Params params) { 6384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 6394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka null, R.styleable.Keyboard, R.attr.keyboardStyle, 0); 6404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0); 6414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int resourceId = a.getResourceId( 6424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_touchPositionCorrectionData, 0); 6434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 6444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (resourceId == 0) { 6454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) 6461e4684ad24914cde713980bb4174810bbf8bae10Jean Chalard Log.e(TAG, "touchPositionCorrectionData is not defined"); 6474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return; 6484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String[] data = context.getResources().getStringArray(resourceId); 6514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mTouchPositionCorrection.load(data); 6524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 654e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok private static void setAdditionalProximityChars(Context context, Params params) { 655e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final String[] additionalChars = 656e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok context.getResources().getStringArray(R.array.additional_proximitychars); 657e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok int currentPrimaryIndex = 0; 658e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok for (int i = 0; i < additionalChars.length; ++i) { 659e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final String additionalChar = additionalChars[i]; 660e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok if (TextUtils.isEmpty(additionalChar)) { 661e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex = 0; 662e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } else if (currentPrimaryIndex == 0) { 663e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex = additionalChar.charAt(0); 664e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok params.mAdditionalProximityChars.put( 665e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex, new ArrayList<Integer>()); 666e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } else if (currentPrimaryIndex != 0) { 667e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final int c = additionalChar.charAt(0); 668e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c); 669e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 670e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 671e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 672e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok 67309f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka public void setAutoGenerate(KeyboardSet.KeysCache keysCache) { 67409f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka mParams.mKeysCache = keysCache; 67509f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka } 67609f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka 6774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Builder<KP> load(int xmlId, KeyboardId id) { 6784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mId = id; 6794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final XmlResourceParser parser = mResources.getXml(xmlId); 6804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 6814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboard(parser); 6824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (XmlPullParserException e) { 6834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Log.w(TAG, "keyboard XML parse error: " + e); 6844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new IllegalArgumentException(e); 6854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (IOException e) { 6864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Log.w(TAG, "keyboard XML parse error: " + e); 6874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException(e); 6884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 6894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parser.close(); 6904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return this; 6924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setTouchPositionCorrectionEnabled(boolean enabled) { 6954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mTouchPositionCorrection.setEnabled(enabled); 6964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Keyboard build() { 6994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return new Keyboard(mParams); 7004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboard(XmlPullParser parser) 7034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 7044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mParams.mId)); 7054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 7064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 7074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 7084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 7094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEYBOARD.equals(tag)) { 7104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardAttributes(parser); 7114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka startKeyboard(); 7124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, false); 7134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 7144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 7154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD); 7164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboardAttributes(XmlPullParser parser) { 7224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int displayWidth = mDisplayMetrics.widthPixels; 7234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray keyboardAttr = mContext.obtainStyledAttributes( 7244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle, 7254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.style.Keyboard); 7264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), 7274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 7284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 7294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int displayHeight = mDisplayMetrics.heightPixels; 7304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardHeight = (int)keyboardAttr.getDimension( 7314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardHeight, displayHeight / 2); 7324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, 7334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); 7344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, 7354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2); 7364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (minKeyboardHeight < 0) { 7374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Specified fraction was negative, so it should be calculated against display 7384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // width. 7394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr, 7404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2); 7414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Params params = mParams; 7434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Keyboard height will not exceed maxKeyboardHeight and will not be less than 7444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // minKeyboardHeight. 7454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mOccupiedHeight = Math.max( 7464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); 7474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mOccupiedWidth = params.mId.mWidth; 7484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr, 7494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0); 7504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr, 7514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0); 7524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr, 7534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardHorizontalEdgesPadding, 7544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mOccupiedWidth, 0); 7554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2 7574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - params.mHorizontalCenterPadding; 7584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr, 7594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, 7604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS); 7614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr, 7624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0); 7634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr, 7644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0); 7654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding 7664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - params.mBottomPadding + params.mVerticalGap; 7674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr, 7684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_rowHeight, params.mBaseHeight, 7694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight / DEFAULT_KEYBOARD_ROWS); 7704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mMoreKeysTemplate = keyboardAttr.getResourceId( 7724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_moreKeysTemplate, 0); 7734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mMaxMiniKeyboardColumn = keyAttr.getInt( 7744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_maxMoreKeysColumn, 5); 7754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mIconsSet.loadIcons(keyboardAttr); 7774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 7784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttr.recycle(); 7794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardAttr.recycle(); 7804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboardContent(XmlPullParser parser, boolean skip) 7844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 7854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 7864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 7874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 7884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 7894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_ROW.equals(tag)) { 7904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Row row = parseRowAttributes(parser); 7914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW)); 7924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!skip) 7934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka startRow(row); 7944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 7954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_INCLUDE.equals(tag)) { 7964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeKeyboardContent(parser, skip); 7974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SWITCH.equals(tag)) { 7984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchKeyboardContent(parser, skip); 7994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyStyle(parser, skip); 8014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW); 8034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 8054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEYBOARD.equals(tag)) { 8074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKeyboard(); 8084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) 8104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || TAG_MERGE.equals(tag)) { 8114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("</%s>", tag)); 8124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka continue; 8154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW); 8174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException { 8234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 8244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard); 8254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 8264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (a.hasValue(R.styleable.Keyboard_horizontalGap)) 8274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap"); 8284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (a.hasValue(R.styleable.Keyboard_verticalGap)) 8294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap"); 8304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return new Row(mResources, mParams, parser, mCurrentY); 8314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 8324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 8334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseRowContent(XmlPullParser parser, Row row, boolean skip) 8374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 8394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 8404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 8414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEY.equals(tag)) { 8434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKey(parser, row, skip); 8444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SPACER.equals(tag)) { 8454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSpacer(parser, row, skip); 8464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_INCLUDE.equals(tag)) { 8474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeRowContent(parser, row, skip); 8484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SWITCH.equals(tag)) { 8494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchRowContent(parser, row, skip); 8504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyStyle(parser, skip); 8524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); 8544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 8564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_ROW.equals(tag)) { 8584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_ROW)); 8594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!skip) 8604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endRow(row); 8614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) 8634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || TAG_MERGE.equals(tag)) { 8644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("</%s>", tag)); 8654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka continue; 8684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); 8704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKey(XmlPullParser parser, Row row, boolean skip) 8764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 8784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY, parser); 8794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Key key = new Key(mResources, mParams, row, parser, mKeyStyles); 8814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />", 8824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode, 8834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Arrays.toString(key.mMoreKeys))); 8844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY, parser); 8854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKey(key); 8864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSpacer(XmlPullParser parser, Row row, boolean skip) 8904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 8924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_SPACER, parser); 8934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Key.Spacer spacer = new Key.Spacer( 8954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mResources, mParams, row, parser, mKeyStyles); 8964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER)); 8974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_SPACER, parser); 8984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKey(spacer); 8994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip) 9034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeInternal(parser, null, skip); 9054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip) 9084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeInternal(parser, row, skip); 9104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip) 9134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 9154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); 9164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 917a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final AttributeSet attr = Xml.asAttributeSet(parser); 918a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final TypedArray keyboardAttr = mResources.obtainAttributes(attr, 9194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include); 920a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final TypedArray keyAttr = mResources.obtainAttributes(attr, 921a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka R.styleable.Keyboard_Key); 9224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int keyboardLayout = 0; 923a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka float savedDefaultKeyWidth = 0; 9244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 925a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka XmlParseUtils.checkAttributeExists(keyboardAttr, 9264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout", 9274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TAG_INCLUDE, parser); 928a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyboardLayout = keyboardAttr.getResourceId( 9294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include_keyboardLayout, 0); 930a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (row != null) { 931a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka savedDefaultKeyWidth = row.getDefaultKeyWidth(); 932a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { 933a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka // Override current x coordinate. 934a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka row.setXPos(row.getKeyX(keyAttr)); 935a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 936a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyWidth)) { 937a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka // Override default key width. 938a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka row.setDefaultKeyWidth(row.getKeyWidth(keyAttr)); 939a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 940a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 9414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 942a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyboardAttr.recycle(); 943a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyAttr.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 { 953a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (row != null) { 954a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka // Restore default key width. 955a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka row.setDefaultKeyWidth(savedDefaultKeyWidth); 956a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 9574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parserForInclude.close(); 9584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseMerge(XmlPullParser parser, Row row, boolean skip) 9634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 9654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 9664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 9674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 9684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_MERGE.equals(tag)) { 9694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 9704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, skip); 9714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 9734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 9754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.ParseException( 9774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "Included keyboard layout must have <merge> root element", parser); 9784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip) 9844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchInternal(parser, null, skip); 9864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip) 9894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchInternal(parser, row, skip); 9914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip) 9944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mParams.mId)); 9964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka boolean selected = false; 9974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 9984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 9994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 10004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 10014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_CASE.equals(tag)) { 10024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka selected |= parseCase(parser, row, selected ? true : skip); 10034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_DEFAULT.equals(tag)) { 10044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka selected |= parseDefault(parser, row, selected ? true : skip); 10054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); 10074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 10094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 10104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_SWITCH.equals(tag)) { 10114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_SWITCH)); 10124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 10134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); 10154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseCase(XmlPullParser parser, Row row, boolean skip) 10214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean selected = parseCaseCondition(parser); 10234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 10244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Processing Rows. 10254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, selected ? skip : true); 10264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Processing Keys. 10284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, selected ? skip : true); 10294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return selected; 10314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseCaseCondition(XmlPullParser parser) { 10344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final KeyboardId id = mParams.mId; 10354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (id == null) 10364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 10374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 10394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case); 10404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 104183306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka final boolean keyboardSetElementMatched = matchTypedValue(a, 104283306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka R.styleable.Keyboard_Case_keyboardSetElement, id.mElementId, 104383306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka KeyboardId.elementIdToName(id.mElementId)); 10444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean modeMatched = matchTypedValue(a, 10454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode)); 10464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean navigateActionMatched = matchBoolean(a, 10474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_navigateAction, id.navigateAction()); 10484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean passwordInputMatched = matchBoolean(a, 10494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_passwordInput, id.passwordInput()); 10504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean hasSettingsKeyMatched = matchBoolean(a, 10514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_hasSettingsKey, id.hasSettingsKey()); 10524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean f2KeyModeMatched = matchInteger(a, 10534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_f2KeyMode, id.f2KeyMode()); 10544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean clobberSettingsKeyMatched = matchBoolean(a, 10554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey); 10564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean shortcutKeyEnabledMatched = matchBoolean(a, 10574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); 10584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean hasShortcutKeyMatched = matchBoolean(a, 10594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); 10604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // As noted at {@link KeyboardId} class, we are interested only in enum value 10614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // masked by {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and 10624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching 10634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // this attribute with id.mImeOptions as integer value is enough for our purpose. 10644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean imeActionMatched = matchInteger(a, 10654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_imeAction, id.imeAction()); 10664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean localeCodeMatched = matchString(a, 10674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_localeCode, id.mLocale.toString()); 10684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean languageCodeMatched = matchString(a, 10694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage()); 10704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean countryCodeMatched = matchString(a, 10714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry()); 107283306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka final boolean selected = keyboardSetElementMatched && modeMatched 107383306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka && navigateActionMatched && passwordInputMatched && hasSettingsKeyMatched 107483306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka && f2KeyModeMatched && clobberSettingsKeyMatched 107583306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka && shortcutKeyEnabledMatched && hasShortcutKeyMatched && imeActionMatched 107683306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka && localeCodeMatched && languageCodeMatched && countryCodeMatched; 107783306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka 107883306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE, 107983306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), 108083306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka "keyboardSetElement"), 10814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), 10824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"), 10834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"), 10844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"), 10854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(KeyboardId.f2KeyModeName( 10864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), "f2KeyMode"), 10874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey, 10884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "clobberSettingsKey"), 10894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled, 10904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "shortcutKeyEnabled"), 10914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"), 10924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(EditorInfoCompatUtils.imeOptionsName( 10934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"), 10944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), "localeCode"), 10954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), 10964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "languageCode"), 10974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"), 10984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Boolean.toString(selected))); 10994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return selected; 11014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 11024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 11034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchInteger(TypedArray a, int index, int value) { 11074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) || a.getInt(index, 0) == value; 11104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchBoolean(TypedArray a, int index, boolean value) { 11134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) || a.getBoolean(index, false) == value; 11164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchString(TypedArray a, int index, String value) { 11194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) 11224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || stringArrayContains(a.getString(index).split("\\|"), value); 11234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchTypedValue(TypedArray a, int index, int intValue, 11264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka String strValue) { 11274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue v = a.peekValue(index); 11304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (v == null) 11314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isIntegerValue(v)) { 11344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return intValue == a.getInt(index, 0); 11354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (isStringValue(v)) { 11364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return stringArrayContains(a.getString(index).split("\\|"), strValue); 11374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return false; 11394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean stringArrayContains(String[] array, String value) { 11424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka for (final String elem : array) { 11434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (elem.equals(value)) 11444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return false; 11474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseDefault(XmlPullParser parser, Row row, boolean skip) 11504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 11514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT)); 11524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 11534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, skip); 11544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 11554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 11564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyStyle(XmlPullParser parser, boolean skip) 11614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException { 11624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), 11634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_KeyStyle); 11644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), 11654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 11664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 11674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) 11684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE 11694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka + "/> needs styleName attribute", parser); 11704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!skip) 11714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); 11724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 11734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyStyleAttr.recycle(); 11744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttrs.recycle(); 11754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void startKeyboard() { 11794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY += mParams.mTopPadding; 11804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mTopEdge = true; 11814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void startRow(Row row) { 11844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka addEdgeSpace(mParams.mHorizontalEdgesPadding, row); 11854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentRow = row; 11864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = true; 11874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 11884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endRow(Row row) { 11914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mCurrentRow == null) 11924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new InflateException("orphant end row tag"); 11934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mRightEdgeKey != null) { 11944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey.markAsRightEdge(mParams); 11954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 11964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka addEdgeSpace(mParams.mHorizontalEdgesPadding, row); 11984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY += row.mRowHeight; 11994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentRow = null; 12004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mTopEdge = false; 12014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endKey(Key key) { 12044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.onAddKey(key); 12054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mLeftEdge) { 12064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka key.markAsLeftEdge(mParams); 12074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = false; 12084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mTopEdge) { 12104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka key.markAsTopEdge(mParams); 12114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = key; 12134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endKeyboard() { 12164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // nothing to do here. 12174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void addEdgeSpace(float width, Row row) { 12204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka row.advanceXPos(width); 12214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = false; 12224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 12234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static float getDimensionOrFraction(TypedArray a, int index, int base, 12264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka float defValue) { 12274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue value = a.peekValue(index); 12284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (value == null) 12294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isFractionValue(value)) { 12314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getFraction(index, base, base, defValue); 12324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (isDimensionValue(value)) { 12334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getDimension(index, defValue); 12344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static int getEnumValue(TypedArray a, int index, int defValue) { 12394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue value = a.peekValue(index); 12404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (value == null) 12414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isIntegerValue(value)) { 12434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getInt(index, defValue); 12444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isFractionValue(TypedValue v) { 12494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_FRACTION; 12504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isDimensionValue(TypedValue v) { 12534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_DIMENSION; 12544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isIntegerValue(TypedValue v) { 12574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; 12584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isStringValue(TypedValue v) { 12614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_STRING; 12624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static String textAttr(String value, String name) { 12654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return value != null ? String.format(" %s=%s", name, value) : ""; 12664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static String booleanAttr(TypedArray a, int index, String name) { 12694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.hasValue(index) 12704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka ? String.format(" %s=%s", name, a.getBoolean(index, false)) : ""; 12714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12735a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka} 1274