Keyboard.java revision 81d4e3cd66a9388c47c7dba55240ddf849b31934
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.keyboard.internal.KeyStyles; 32c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport com.android.inputmethod.latin.XmlParseUtils; 36b7758d6f912093747d4b18fbc8d1dcd77c7d1f9bTadashi G. Takaoka 374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport org.xmlpull.v1.XmlPullParser; 384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport org.xmlpull.v1.XmlPullParserException; 394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport java.io.IOException; 41e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatokimport java.util.ArrayList; 424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport java.util.Arrays; 438da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaokaimport java.util.Collections; 442013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaokaimport java.util.HashMap; 454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaokaimport java.util.HashSet; 46e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatokimport java.util.List; 47167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaokaimport java.util.Map; 48167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaokaimport java.util.Set; 495a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 505a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka/** 515a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard 525a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * consists of rows of keys. 535a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p> 545a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <pre> 555a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Keyboard 565a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:keyWidth="%10p" 575a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:keyHeight="50px" 585a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:horizontalGap="2px" 595a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * latin:verticalGap="2px" > 605a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Row latin:keyWidth="32px" > 615a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * <Key latin:keyLabel="A" /> 625a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * ... 635a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </Row> 645a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * ... 655a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </Keyboard> 665a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * </pre> 675a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka */ 685a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapublic class Keyboard { 697dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka private static final String TAG = Keyboard.class.getSimpleName(); 707dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka 71ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka /** Some common keys code. Must be positive. 72ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka * These should be aligned with values/keycodes.xml 73ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka */ 74571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_ENTER = '\n'; 75571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_TAB = '\t'; 76571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_SPACE = ' '; 77571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_PERIOD = '.'; 780730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_DASH = '-'; 790730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_SINGLE_QUOTE = '\''; 800730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard public static final int CODE_DOUBLE_QUOTE = '"'; 812b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // TODO: Check how this should work for right-to-left languages. It seems to stand 822b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // that for rtl languages, a closing parenthesis is a left parenthesis. Is this 832b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard // managed by the font? Or is it a different char? 842b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_PARENTHESIS = ')'; 852b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_SQUARE_BRACKET = ']'; 862b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_CURLY_BRACKET = '}'; 872b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard public static final int CODE_CLOSING_ANGLE_BRACKET = '>'; 888cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka private static final int MINIMUM_LETTER_CODE = CODE_TAB; 892b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard 908cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka /** Special keys code. Must be negative. 91ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka * These should be aligned with values/keycodes.xml 92ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka */ 93571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka public static final int CODE_SHIFT = -1; 94e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka public static final int CODE_SWITCH_ALPHA_SYMBOL = -2; 957a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka public static final int CODE_OUTPUT_TEXT = -3; 967a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka public static final int CODE_DELETE = -4; 977a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka public static final int CODE_SETTINGS = -5; 987a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka public static final int CODE_SHORTCUT = -6; 997a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka public static final int CODE_ACTION_ENTER = -7; 10005bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka public static final int CODE_ACTION_NEXT = -8; 10105bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka public static final int CODE_ACTION_PREVIOUS = -9; 10281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka public static final int CODE_LANGUAGE_SWITCH = -10; 103c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka // Code value representing the code is not specified. 10481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka public static final int CODE_UNSPECIFIED = -11; 1055a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 106167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka public final KeyboardId mId; 10763584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka public final int mThemeId; 108167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka 109167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka /** Total height of the keyboard, including the padding and keys */ 1108da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mOccupiedHeight; 1118da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka /** Total width of the keyboard, including the padding and keys */ 1128da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mOccupiedWidth; 113167e77f17084da5c223a3a790d3dd3d749e68ae3Tadashi G. Takaoka 1148fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka /** The padding above the keyboard */ 1158fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka public final int mTopPadding; 1165a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka /** Default gap between rows */ 1178da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mVerticalGap; 1188da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1198fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka public final int mMostCommonKeyHeight; 1208da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final int mMostCommonKeyWidth; 1215a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1229d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka /** More keys keyboard template */ 1239d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public final int mMoreKeysTemplate; 1249b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka 1252affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka /** Maximum column for more keys keyboard */ 1262affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka public final int mMaxMoreKeysKeyboardColumn; 1279b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka 1288da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka /** List of keys and icons in this keyboard */ 1294a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka public final Set<Key> mKeys; 1304a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka public final Set<Key> mShiftKeys; 1318da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka public final KeyboardIconsSet mIconsSet; 1326fb97bf71cee2a0775410a05478ed6a667aa847fTadashi G. Takaoka 1332013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka private final Map<Integer, Key> mKeyCache = new HashMap<Integer, Key>(); 134c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 1358fbd55229243cb66c03d5ea1f79dfb39f596590dsatok private final ProximityInfo mProximityInfo; 1368fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 137e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok public final Map<Integer, List<Integer>> mAdditionalProximityChars; 138e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok 1394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Keyboard(Params params) { 1408da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mId = params.mId; 14163584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka mThemeId = params.mThemeId; 1428da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mOccupiedHeight = params.mOccupiedHeight; 1438da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mOccupiedWidth = params.mOccupiedWidth; 1448fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka mMostCommonKeyHeight = params.mMostCommonKeyHeight; 1458da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mMostCommonKeyWidth = params.mMostCommonKeyWidth; 1469d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysTemplate = params.mMoreKeysTemplate; 1472affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn; 1488da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1498fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka mTopPadding = params.mTopPadding; 1508da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mVerticalGap = params.mVerticalGap; 1518da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 1524a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka mKeys = Collections.unmodifiableSet(params.mKeys); 1534a019a9c96b3a628265ef49f5522f20aeb5856cfTadashi G. Takaoka mShiftKeys = Collections.unmodifiableSet(params.mShiftKeys); 1548da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mIconsSet = params.mIconsSet; 155e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok mAdditionalProximityChars = params.mAdditionalProximityChars; 1565a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1570d5494c66ac3e5947040e8148091163a1c8716f7satok mProximityInfo = new ProximityInfo( 1588da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, 159e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection, 160e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok params.mAdditionalProximityChars); 1618fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1628fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 163043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard public ProximityInfo getProximityInfo() { 164043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard return mProximityInfo; 1655a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 1665a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 1672013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka public Key getKey(int code) { 1688cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka if (code == CODE_UNSPECIFIED) { 169623d0155b6a316fdc9335370cdd4005bbb474ef3Tadashi G. Takaoka return null; 170623d0155b6a316fdc9335370cdd4005bbb474ef3Tadashi G. Takaoka } 1712013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka final Integer keyCode = code; 1722013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (mKeyCache.containsKey(keyCode)) { 1732013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return mKeyCache.get(keyCode); 1742013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1752013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 1762013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka for (final Key key : mKeys) { 1772013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka if (key.mCode == code) { 1782013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka mKeyCache.put(keyCode, key); 1792013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return key; 1802013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1812013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1822013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka mKeyCache.put(keyCode, null); 1832013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka return null; 1842013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka } 1852013bab89ca2f82589f99d98d9cf3b41ea5aac65Tadashi G. Takaoka 186c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka // TODO: Remove this method. 1875a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka public boolean isShiftedOrShiftLocked() { 188ede2133cb137a48aabd2aefc464f68edb7fd2514Tadashi G. Takaoka // Alphabet mode have unshifted, manual shifted, automatic shifted, shift locked, and 189ede2133cb137a48aabd2aefc464f68edb7fd2514Tadashi G. Takaoka // shift lock shifted element. So that unshifed element is the only one that is NOT in 190ede2133cb137a48aabd2aefc464f68edb7fd2514Tadashi G. Takaoka // shifted or shift locked state. 191ede2133cb137a48aabd2aefc464f68edb7fd2514Tadashi G. Takaoka return mId.isAlphabetKeyboard() && mId.mElementId != KeyboardId.ELEMENT_ALPHABET; 192571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka } 193571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka 194ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka public static boolean isLetterCode(int code) { 1958cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka return code >= MINIMUM_LETTER_CODE; 196ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka } 197ee4be6e3c6eed719683fd3019d48365ba76790e2Tadashi G. Takaoka 1984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Params { 1994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public KeyboardId mId; 2004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mThemeId; 2014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Total height and width of the keyboard, including the paddings and keys */ 2034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mOccupiedHeight; 2044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mOccupiedWidth; 2054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Base height and width of the keyboard used to calculate rows' or keys' heights and 2074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * widths 2084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 2094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBaseHeight; 2104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBaseWidth; 2114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mTopPadding; 2134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mBottomPadding; 2144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalEdgesPadding; 2154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalCenterPadding; 2164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mDefaultRowHeight; 2184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mDefaultKeyWidth; 2194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mHorizontalGap; 2204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mVerticalGap; 2214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMoreKeysTemplate; 2232affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka public int mMaxMoreKeysKeyboardColumn; 2244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int GRID_WIDTH; 2264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int GRID_HEIGHT; 2274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final Set<Key> mKeys = new HashSet<Key>(); 2294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final Set<Key> mShiftKeys = new HashSet<Key>(); 2304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); 231e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok // TODO: Should be in Key instead of Keyboard.Params? 232e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok public final Map<Integer, List<Integer>> mAdditionalProximityChars = 233e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok new HashMap<Integer, List<Integer>>(); 2344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 23509f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka public KeyboardSet.KeysCache mKeysCache; 23609f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka 2374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMostCommonKeyHeight = 0; 2384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int mMostCommonKeyWidth = 0; 2394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final TouchPositionCorrection mTouchPositionCorrection = 2414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka new TouchPositionCorrection(); 2424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class TouchPositionCorrection { 2444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3; 2454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public boolean mEnabled; 2474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mXs; 2484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mYs; 2494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float[] mRadii; 2504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void load(String[] data) { 2524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int dataLength = data.length; 2534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) { 2544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) 2554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException( 2564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "the size of touch position correction data is invalid"); 2574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return; 2584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE; 2614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs = new float[length]; 2624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs = new float[length]; 2634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii = new float[length]; 2644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 2654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka for (int i = 0; i < dataLength; ++i) { 2664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE; 2674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE; 2684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final float value = Float.parseFloat(data[i]); 2694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (type == 0) { 2704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs[index] = value; 2714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (type == 1) { 2724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs[index] = value; 2734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 2744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii[index] = value; 2754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (NumberFormatException e) { 2784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) { 2794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException( 2804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "the number format for touch position correction data is invalid"); 2814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mXs = null; 2834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mYs = null; 2844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRadii = null; 2854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setEnabled(boolean enabled) { 2894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mEnabled = enabled; 2904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public boolean isValid() { 2934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mEnabled && mXs != null && mYs != null && mRadii != null 2944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0; 2954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 2974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 2984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected void clearKeys() { 2994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeys.clear(); 3004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mShiftKeys.clear(); 3014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka clearHistogram(); 3024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 30409f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka public void onAddKey(Key newKey) { 30509f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka final Key key = (mKeysCache != null) ? mKeysCache.get(newKey) : newKey; 3064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeys.add(key); 3074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka updateHistogram(key); 3084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (key.mCode == Keyboard.CODE_SHIFT) { 3094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mShiftKeys.add(key); 3104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mMaxHeightCount = 0; 3144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mMaxWidthCount = 0; 3154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>(); 3164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>(); 3174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void clearHistogram() { 3194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyHeight = 0; 3204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxHeightCount = 0; 3214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mHeightHistogram.clear(); 3224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxWidthCount = 0; 3244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyWidth = 0; 3254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mWidthHistogram.clear(); 3264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) { 3294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1; 3304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka histogram.put(key, count); 3314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return count; 3324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void updateHistogram(Key key) { 3354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Integer height = key.mHeight + key.mVerticalGap; 3364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int heightCount = updateHistogramCounter(mHeightHistogram, height); 3374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (heightCount > mMaxHeightCount) { 3384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxHeightCount = heightCount; 3394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyHeight = height; 3404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Integer width = key.mWidth + key.mHorizontalGap; 3434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthCount = updateHistogramCounter(mWidthHistogram, width); 3444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (widthCount > mMaxWidthCount) { 3454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMaxWidthCount = widthCount; 3464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mMostCommonKeyWidth = width; 3474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 3504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3515a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka /** 3520c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka * Returns the array of the keys that are closest to the given point. 3535a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * @param x the x-coordinate of the point 3545a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * @param y the y-coordinate of the point 3550c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka * @return the array of the nearest keys to the given point. If the given 3565a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka * point is out of range, then an array of size zero is returned. 3575a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka */ 3580c0ca874febee38fb5cb2c85c11ddd46cdf2b859Tadashi G. Takaoka public Key[] getNearestKeys(int x, int y) { 3594f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa // Avoid dead pixels at edges of the keyboard 3604f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1)); 3614f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa final int adjustedY = Math.max(0, Math.min(y, mOccupiedHeight - 1)); 3624f7d278af62a89ef3f45cc9ebbfb076a5a352c76Ken Wakasa return mProximityInfo.getNearestKeys(adjustedX, adjustedY); 3635a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 36463584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka 365e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok public Map<Integer, List<Integer>> getAdditionalProximityChars() { 366e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok return mAdditionalProximityChars; 367e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 368e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok 3697dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka public static String printableCode(int code) { 3707dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka switch (code) { 3717dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SHIFT: return "shift"; 3727dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SWITCH_ALPHA_SYMBOL: return "symbol"; 3738cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka case CODE_OUTPUT_TEXT: return "text"; 3747dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_DELETE: return "delete"; 375a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka case CODE_SETTINGS: return "settings"; 3767dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_SHORTCUT: return "shortcut"; 3777a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka case CODE_ACTION_ENTER: return "actionEnter"; 37805bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka case CODE_ACTION_NEXT: return "actionNext"; 37905bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka case CODE_ACTION_PREVIOUS: return "actionPrevious"; 3807dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka case CODE_UNSPECIFIED: return "unspec"; 381ca2f051cc173acc3bce384ebfe08068564bc8e07Tadashi G. Takaoka case CODE_TAB: return "tab"; 382ca2f051cc173acc3bce384ebfe08068564bc8e07Tadashi G. Takaoka case CODE_ENTER: return "enter"; 3837dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka default: 3842a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code <= 0) Log.w(TAG, "Unknown non-positive key code=" + code); 3852a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code < CODE_SPACE) return String.format("'\\u%02x'", code); 3862a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka if (code < 0x100) return String.format("'%c'", code); 3872a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka return String.format("'\\u%04x'", code); 3887dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka } 3897dfd5a3e833e14d5bf90d728d5a50b40c8a927d2Tadashi G. Takaoka } 3904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 3914087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka public static String toThemeName(int themeId) { 3924087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka // This should be aligned with theme-*.xml resource files' themeId attribute. 3934087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka switch (themeId) { 3944087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 0: return "Basic"; 3954087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 1: return "BasicHighContrast"; 3964087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 5: return "IceCreamSandwich"; 3974087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 6: return "Stone"; 3984087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 7: return "StoneBold"; 3994087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka case 8: return "GingerBread"; 4004087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka default: return null; 4014087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka } 4024087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka } 4034087ba69faec0dd89fae7d53d7527448091e0aadTadashi G. Takaoka 4044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** 4054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Keyboard Building helper. 4064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * 4074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * This class parses Keyboard XML file and eventually build a Keyboard. 4084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * The Keyboard XML file looks like: 4094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/keyboard.xml --< 4114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Keyboard keyboard_attributes*< 4124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Keyboard Content --< 4134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Row row_attributes*< 4144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Row Content --< 4154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Spacer horizontalGap="0.2in" /< 4174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >include keyboardLayout="@xml/other_keys"< 4184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Row< 4204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >include keyboardLayout="@xml/other_rows"< 4214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Keyboard< 4234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * The XML file which is included in other file must have >merge< as root element, 4254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * such as: 4264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/other_keys.xml --< 4284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >merge< 4294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/merge< 4324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * and 4344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/other_rows.xml --< 4364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >merge< 4374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Row row_attributes*< 4384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Row< 4404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/merge< 4424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * You can also use switch-case-default tags to select Rows and Keys. 4444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >switch< 4464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case case_attribute*< 4474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Any valid tags at switch position --< 4484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >default< 4514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Any valid tags at switch position --< 4524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/default< 4534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/switch< 4544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * You can declare Key style and specify styles within Key tags. 4564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >switch< 4584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case mode="email"< 4594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >key-style styleName="f1-key" parentStyle="modifier-key" 4604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * keyLabel=".com" 4614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * /< 4624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case mode="url"< 4644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >key-style styleName="f1-key" parentStyle="modifier-key" 4654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * keyLabel="http://" 4664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * /< 4674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/switch< 4694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key keyStyle="shift-key" ... /< 4714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 4734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Builder<KP extends Params> { 4757a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private static final String BUILDER_TAG = "Keyboard.Builder"; 4764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final boolean DEBUG = false; 4774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Keyboard XML Tags 4794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_KEYBOARD = "Keyboard"; 4804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_ROW = "Row"; 4814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_KEY = "Key"; 4824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_SPACER = "Spacer"; 4834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_INCLUDE = "include"; 4844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_MERGE = "merge"; 4854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_SWITCH = "switch"; 4864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_CASE = "case"; 4874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_DEFAULT = "default"; 4884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static final String TAG_KEY_STYLE = "key-style"; 4894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int DEFAULT_KEYBOARD_COLUMNS = 10; 4914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int DEFAULT_KEYBOARD_ROWS = 4; 4924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final KP mParams; 4944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final Context mContext; 4954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final Resources mResources; 4964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final DisplayMetrics mDisplayMetrics; 4974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mCurrentY = 0; 4994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Row mCurrentRow = null; 5004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean mLeftEdge; 5014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean mTopEdge; 5024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Key mRightEdgeKey = null; 5034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final KeyStyles mKeyStyles = new KeyStyles(); 5044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** 5064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. 5074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Some of the key size defaults can be overridden per row from what the {@link Keyboard} 5084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * defines. 5094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 5104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Row { 5114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyWidth enum constants 5124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_NOT_ENUM = 0; 5134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_FILL_RIGHT = -1; 5144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_FILL_BOTH = -2; 5154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Params mParams; 5174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Default width of a key in this row. */ 518a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka private float mDefaultKeyWidth; 5194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Default height of a key in this row. */ 5204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final int mRowHeight; 5214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final int mCurrentY; 5234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Will be updated by {@link Key}'s constructor. 5244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private float mCurrentX; 5254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Row(Resources res, Params params, XmlPullParser parser, int y) { 5274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams = params; 5284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 5294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard); 5304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRowHeight = (int)Builder.getDimensionOrFraction(keyboardAttr, 5314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_rowHeight, 5324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight, params.mDefaultRowHeight); 5334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardAttr.recycle(); 5344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 5354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 5364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mDefaultKeyWidth = Builder.getDimensionOrFraction(keyAttr, 5374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, 5384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth, params.mDefaultKeyWidth); 5394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttr.recycle(); 5404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY = y; 5424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX = 0.0f; 5434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 545a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public float getDefaultKeyWidth() { 546a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka return mDefaultKeyWidth; 547a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 548a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 549a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public void setDefaultKeyWidth(float defaultKeyWidth) { 550a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka mDefaultKeyWidth = defaultKeyWidth; 551a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 552a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 5534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setXPos(float keyXPos) { 5544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX = keyXPos; 5554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void advanceXPos(float width) { 5584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX += width; 5594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int getKeyY() { 5624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentY; 5634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float getKeyX(TypedArray keyAttr) { 5664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthType = Builder.getEnumValue(keyAttr, 5674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 5684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (widthType == KEYWIDTH_FILL_BOTH) { 5694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillBoth, the key width should start right after the nearest 5704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // key on the left hand side. 5714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentX; 5724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardRightEdge = mParams.mOccupiedWidth 5754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - mParams.mHorizontalEdgesPadding; 5764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { 5774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final float keyXPos = Builder.getDimensionOrFraction(keyAttr, 5784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0); 5794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (keyXPos < 0) { 5804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyXPos is negative, the actual x-coordinate will be 5814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyboardWidth + keyXPos. 5824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyXPos shouldn't be less than mCurrentX because drawable area for this 5834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // key starts at mCurrentX. Or, this key will overlaps the adjacent key on 5844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // its left hand side. 5854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return Math.max(keyXPos + keyboardRightEdge, mCurrentX); 5864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 5874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return keyXPos + mParams.mHorizontalEdgesPadding; 5884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentX; 5914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 593a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public float getKeyWidth(TypedArray keyAttr) { 594a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka return getKeyWidth(keyAttr, mCurrentX); 595a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 596a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 5974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float getKeyWidth(TypedArray keyAttr, float keyXPos) { 5984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthType = Builder.getEnumValue(keyAttr, 5994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 6004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka switch (widthType) { 6014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka case KEYWIDTH_FILL_RIGHT: 6024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka case KEYWIDTH_FILL_BOTH: 6034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardRightEdge = 6044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding; 6054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillRight, the actual key width will be determined to fill 6064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // out the area up to the right edge of the keyboard. 6074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillBoth, the actual key width will be determined to fill out 6084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the area between the nearest key on the left hand side and the right edge of 6094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the keyboard. 6104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return keyboardRightEdge - keyXPos; 6114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka default: // KEYWIDTH_NOT_ENUM 6124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return Builder.getDimensionOrFraction(keyAttr, 6134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, 6144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mBaseWidth, mDefaultKeyWidth); 6154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Builder(Context context, KP params) { 6204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mContext = context; 6214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Resources res = context.getResources(); 6224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mResources = res; 6234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mDisplayMetrics = res.getDisplayMetrics(); 6244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams = params; 6264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka setTouchPositionCorrectionData(context, params); 628e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok setAdditionalProximityChars(context, params); 6294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); 6314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); 6324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static void setTouchPositionCorrectionData(Context context, Params params) { 6354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 6364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka null, R.styleable.Keyboard, R.attr.keyboardStyle, 0); 6374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0); 6384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int resourceId = a.getResourceId( 6394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_touchPositionCorrectionData, 0); 6404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 6414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (resourceId == 0) { 6424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) 6437a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.e(BUILDER_TAG, "touchPositionCorrectionData is not defined"); 6444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return; 6454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String[] data = context.getResources().getStringArray(resourceId); 6484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mTouchPositionCorrection.load(data); 6494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 651e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok private static void setAdditionalProximityChars(Context context, Params params) { 652e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final String[] additionalChars = 653e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok context.getResources().getStringArray(R.array.additional_proximitychars); 654e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok int currentPrimaryIndex = 0; 655e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok for (int i = 0; i < additionalChars.length; ++i) { 656e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final String additionalChar = additionalChars[i]; 657e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok if (TextUtils.isEmpty(additionalChar)) { 658e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex = 0; 659e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } else if (currentPrimaryIndex == 0) { 660e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex = additionalChar.charAt(0); 661e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok params.mAdditionalProximityChars.put( 662e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex, new ArrayList<Integer>()); 663e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } else if (currentPrimaryIndex != 0) { 664e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final int c = additionalChar.charAt(0); 665e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c); 666e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 667e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 668e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 669e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok 67009f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka public void setAutoGenerate(KeyboardSet.KeysCache keysCache) { 67109f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka mParams.mKeysCache = keysCache; 67209f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka } 67309f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka 6744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Builder<KP> load(int xmlId, KeyboardId id) { 6754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mId = id; 6764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final XmlResourceParser parser = mResources.getXml(xmlId); 6774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 6784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboard(parser); 6794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (XmlPullParserException e) { 6807a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.w(BUILDER_TAG, "keyboard XML parse error: " + e); 6814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new IllegalArgumentException(e); 6824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (IOException e) { 6837a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.w(BUILDER_TAG, "keyboard XML parse error: " + e); 6844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException(e); 6854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 6864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parser.close(); 6874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return this; 6894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setTouchPositionCorrectionEnabled(boolean enabled) { 6924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mTouchPositionCorrection.setEnabled(enabled); 6934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Keyboard build() { 6964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return new Keyboard(mParams); 6974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6997a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private int mIndent; 7007a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private static final String SPACES = " "; 7017a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7027a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private static String spaces(int count) { 7037a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka return (count < SPACES.length()) ? SPACES.substring(0, count) : SPACES; 7047a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 7057a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7067a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void startTag(String format, Object ... args) { 7077a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args)); 7087a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 7097a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7107a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void endTag(String format, Object ... args) { 7117a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.d(BUILDER_TAG, String.format(spaces(mIndent-- * 2) + format, args)); 7127a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 7137a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7147a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void startEndTag(String format, Object ... args) { 7157a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args)); 7167a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka mIndent--; 7177a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 7187a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboard(XmlPullParser parser) 7204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 7217a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s> %s", TAG_KEYBOARD, mParams.mId); 7224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 7234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 7244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 7254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 7264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEYBOARD.equals(tag)) { 7274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardAttributes(parser); 7284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka startKeyboard(); 7294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, false); 7304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 7314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 7324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD); 7334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboardAttributes(XmlPullParser parser) { 7394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int displayWidth = mDisplayMetrics.widthPixels; 7404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray keyboardAttr = mContext.obtainStyledAttributes( 7414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle, 7424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.style.Keyboard); 7434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), 7444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 7454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 7464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int displayHeight = mDisplayMetrics.heightPixels; 7474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardHeight = (int)keyboardAttr.getDimension( 7484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardHeight, displayHeight / 2); 7494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, 7504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); 7514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, 7524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2); 7534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (minKeyboardHeight < 0) { 7544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Specified fraction was negative, so it should be calculated against display 7554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // width. 7564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr, 7574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2); 7584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Params params = mParams; 7604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Keyboard height will not exceed maxKeyboardHeight and will not be less than 7614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // minKeyboardHeight. 7624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mOccupiedHeight = Math.max( 7634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); 7644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mOccupiedWidth = params.mId.mWidth; 7654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr, 7664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0); 7674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr, 7684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0); 7694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr, 7704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardHorizontalEdgesPadding, 7714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mOccupiedWidth, 0); 7724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2 7744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - params.mHorizontalCenterPadding; 7754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr, 7764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, 7774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS); 7784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr, 7794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0); 7804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr, 7814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0); 7824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding 7834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - params.mBottomPadding + params.mVerticalGap; 7844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr, 7854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_rowHeight, params.mBaseHeight, 7864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight / DEFAULT_KEYBOARD_ROWS); 7874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mMoreKeysTemplate = keyboardAttr.getResourceId( 7894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_moreKeysTemplate, 0); 7902affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka params.mMaxMoreKeysKeyboardColumn = keyAttr.getInt( 7914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_maxMoreKeysColumn, 5); 7924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mIconsSet.loadIcons(keyboardAttr); 7944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 7954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttr.recycle(); 7964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardAttr.recycle(); 7974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboardContent(XmlPullParser parser, boolean skip) 8014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 8034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 8044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 8054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_ROW.equals(tag)) { 8074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Row row = parseRowAttributes(parser); 8087a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s>%s", TAG_ROW, skip ? " skipped" : ""); 8097a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (!skip) { 8104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka startRow(row); 8117a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 8124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 8134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_INCLUDE.equals(tag)) { 8144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeKeyboardContent(parser, skip); 8154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SWITCH.equals(tag)) { 8164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchKeyboardContent(parser, skip); 8174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyStyle(parser, skip); 8194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW); 8214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 8234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8247a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) endTag("</%s>", tag); 8254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEYBOARD.equals(tag)) { 8264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKeyboard(); 8274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) 8294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || TAG_MERGE.equals(tag)) { 8304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW); 8334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException { 8394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 8404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard); 8414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 8424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (a.hasValue(R.styleable.Keyboard_horizontalGap)) 8434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap"); 8444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (a.hasValue(R.styleable.Keyboard_verticalGap)) 8454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap"); 8464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return new Row(mResources, mParams, parser, mCurrentY); 8474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 8484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 8494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseRowContent(XmlPullParser parser, Row row, boolean skip) 8534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 8554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 8564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 8574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEY.equals(tag)) { 8594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKey(parser, row, skip); 8604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SPACER.equals(tag)) { 8614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSpacer(parser, row, skip); 8624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_INCLUDE.equals(tag)) { 8634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeRowContent(parser, row, skip); 8644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SWITCH.equals(tag)) { 8654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchRowContent(parser, row, skip); 8664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyStyle(parser, skip); 8684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); 8704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 8724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8737a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) endTag("</%s>", tag); 8744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_ROW.equals(tag)) { 8757a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (!skip) { 8764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endRow(row); 8777a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 8784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) 8804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || TAG_MERGE.equals(tag)) { 8814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); 8844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKey(XmlPullParser parser, Row row, boolean skip) 8904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 8924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY, parser); 8937a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY); 8944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Key key = new Key(mResources, mParams, row, parser, mKeyStyles); 8967a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) { 8977a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY, 8987a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka (key.isEnabled() ? "" : " disabled"), key, 8997a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Arrays.toString(key.mMoreKeys)); 9007a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 9014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY, parser); 9024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKey(key); 9034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSpacer(XmlPullParser parser, Row row, boolean skip) 9074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 9094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_SPACER, parser); 9107a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startEndTag("<%s /> skipped", TAG_SPACER); 9114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Key.Spacer spacer = new Key.Spacer( 9134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mResources, mParams, row, parser, mKeyStyles); 9147a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startEndTag("<%s />", TAG_SPACER); 9154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_SPACER, parser); 9164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKey(spacer); 9174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip) 9214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeInternal(parser, null, skip); 9234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip) 9264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeInternal(parser, row, skip); 9284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip) 9314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 9334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); 9347a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startEndTag("</%s> skipped", TAG_INCLUDE); 9354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 936a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final AttributeSet attr = Xml.asAttributeSet(parser); 937a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final TypedArray keyboardAttr = mResources.obtainAttributes(attr, 9384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include); 939a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final TypedArray keyAttr = mResources.obtainAttributes(attr, 940a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka R.styleable.Keyboard_Key); 9414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int keyboardLayout = 0; 942a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka float savedDefaultKeyWidth = 0; 9434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 944a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka XmlParseUtils.checkAttributeExists(keyboardAttr, 9454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout", 9464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TAG_INCLUDE, parser); 947a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyboardLayout = keyboardAttr.getResourceId( 9484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include_keyboardLayout, 0); 949a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (row != null) { 950a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka savedDefaultKeyWidth = row.getDefaultKeyWidth(); 951a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { 952a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka // Override current x coordinate. 953a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka row.setXPos(row.getKeyX(keyAttr)); 954a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 955a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyWidth)) { 956a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka // Override default key width. 957a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka row.setDefaultKeyWidth(row.getKeyWidth(keyAttr)); 958a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 959a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 9604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 961a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyboardAttr.recycle(); 962a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyAttr.recycle(); 9634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); 9667a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) { 9677a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka startEndTag("<%s keyboardLayout=%s />",TAG_INCLUDE, 9687a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka mResources.getResourceEntryName(keyboardLayout)); 9697a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 9704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout); 9714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 9724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseMerge(parserForInclude, row, skip); 9734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 974a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (row != null) { 975a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka // Restore default key width. 976a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka row.setDefaultKeyWidth(savedDefaultKeyWidth); 977a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 9784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parserForInclude.close(); 9794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseMerge(XmlPullParser parser, Row row, boolean skip) 9844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9857a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s>", TAG_MERGE); 9864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 9874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 9884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 9894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 9904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_MERGE.equals(tag)) { 9914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 9924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, skip); 9934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 9954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 9974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.ParseException( 9994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "Included keyboard layout must have <merge> root element", parser); 10004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip) 10064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchInternal(parser, null, skip); 10084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip) 10114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchInternal(parser, row, skip); 10134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip) 10164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10177a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s> %s", TAG_SWITCH, mParams.mId); 10184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka boolean selected = false; 10194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 10204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 10214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 10224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 10234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_CASE.equals(tag)) { 10244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka selected |= parseCase(parser, row, selected ? true : skip); 10254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_DEFAULT.equals(tag)) { 10264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka selected |= parseDefault(parser, row, selected ? true : skip); 10274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); 10294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 10314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 10324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_SWITCH.equals(tag)) { 10337a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) endTag("</%s>", TAG_SWITCH); 10344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 10354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); 10374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseCase(XmlPullParser parser, Row row, boolean skip) 10434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean selected = parseCaseCondition(parser); 10454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 10464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Processing Rows. 10474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, selected ? skip : true); 10484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Processing Keys. 10504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, selected ? skip : true); 10514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return selected; 10534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseCaseCondition(XmlPullParser parser) { 10564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final KeyboardId id = mParams.mId; 10574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (id == null) 10584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 10594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 10614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case); 10624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 106383306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka final boolean keyboardSetElementMatched = matchTypedValue(a, 106483306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka R.styleable.Keyboard_Case_keyboardSetElement, id.mElementId, 106583306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka KeyboardId.elementIdToName(id.mElementId)); 10664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean modeMatched = matchTypedValue(a, 10674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode)); 106805bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka final boolean navigateNextMatched = matchBoolean(a, 106905bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka R.styleable.Keyboard_Case_navigateNext, id.navigateNext()); 107005bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka final boolean navigatePreviousMatched = matchBoolean(a, 107105bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka R.styleable.Keyboard_Case_navigatePrevious, id.navigatePrevious()); 10724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean passwordInputMatched = matchBoolean(a, 10734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_passwordInput, id.passwordInput()); 10744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean clobberSettingsKeyMatched = matchBoolean(a, 10754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey); 10764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean shortcutKeyEnabledMatched = matchBoolean(a, 10774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); 10784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean hasShortcutKeyMatched = matchBoolean(a, 10794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); 108081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka final boolean languageSwitchKeyEnabledMatched = matchBoolean(a, 108181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka R.styleable.Keyboard_Case_languageSwitchKeyEnabled, 108281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka id.mLanguageSwitchKeyEnabled); 10837a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka final boolean isMultiLineMatched = matchBoolean(a, 10847a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine()); 10854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean imeActionMatched = matchInteger(a, 10864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_imeAction, id.imeAction()); 10874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean localeCodeMatched = matchString(a, 10884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_localeCode, id.mLocale.toString()); 10894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean languageCodeMatched = matchString(a, 10904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage()); 10914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean countryCodeMatched = matchString(a, 10924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry()); 109383306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka final boolean selected = keyboardSetElementMatched && modeMatched 109405bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka && navigateNextMatched && navigatePreviousMatched && passwordInputMatched 109597bde43740d8ba7f8aedde35d20621823140966cTadashi G. Takaoka && clobberSettingsKeyMatched && shortcutKeyEnabledMatched 109681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched 109781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && isMultiLineMatched && imeActionMatched && localeCodeMatched 109881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && languageCodeMatched && countryCodeMatched; 10997a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 11007a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) { 110181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, 11027a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), 11037a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "keyboardSetElement"), 11047a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), 110505bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_imeAction), 110605bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka "imeAction"), 110705bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_navigateNext, 110805bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka "navigateNext"), 110905bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_navigatePrevious, 111005bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka "navigatePrevious"), 11117a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey, 11127a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "clobberSettingsKey"), 111305bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, 111405bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka "passwordInput"), 11157a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled, 11167a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "shortcutKeyEnabled"), 11177a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, 11187a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "hasShortcutKey"), 111981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_languageSwitchKeyEnabled, 112081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka "languageSwitchKeyEnabled"), 11217a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine, 11227a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "isMultiLine"), 11237a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), 11247a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "localeCode"), 11257a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), 11267a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "languageCode"), 11277a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), 11287a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "countryCode"), 11297a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka selected ? "" : " skipped"); 11307a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return selected; 11334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 11344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 11354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchInteger(TypedArray a, int index, int value) { 11394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) || a.getInt(index, 0) == value; 11424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchBoolean(TypedArray a, int index, boolean value) { 11454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) || a.getBoolean(index, false) == value; 11484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchString(TypedArray a, int index, String value) { 11514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) 11544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || stringArrayContains(a.getString(index).split("\\|"), value); 11554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchTypedValue(TypedArray a, int index, int intValue, 11584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka String strValue) { 11594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue v = a.peekValue(index); 11624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (v == null) 11634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isIntegerValue(v)) { 11664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return intValue == a.getInt(index, 0); 11674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (isStringValue(v)) { 11684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return stringArrayContains(a.getString(index).split("\\|"), strValue); 11694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return false; 11714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean stringArrayContains(String[] array, String value) { 11744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka for (final String elem : array) { 11754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (elem.equals(value)) 11764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return false; 11794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseDefault(XmlPullParser parser, Row row, boolean skip) 11824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 11837a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s>", TAG_DEFAULT); 11844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 11854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, skip); 11864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 11874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 11884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyStyle(XmlPullParser parser, boolean skip) 11937a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka throws XmlPullParserException, IOException { 11944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), 11954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_KeyStyle); 11964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), 11974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 11984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 11994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) 12004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE 12014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka + "/> needs styleName attribute", parser); 12027a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) { 12037a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka startEndTag("<%s styleName=%s />%s", TAG_KEY_STYLE, 12047a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName), 12057a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka skip ? " skipped" : ""); 12067a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!skip) 12084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); 12094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 12104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyStyleAttr.recycle(); 12114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttrs.recycle(); 12124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12137a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY_STYLE, parser); 12144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void startKeyboard() { 12174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY += mParams.mTopPadding; 12184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mTopEdge = true; 12194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void startRow(Row row) { 12224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka addEdgeSpace(mParams.mHorizontalEdgesPadding, row); 12234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentRow = row; 12244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = true; 12254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 12264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endRow(Row row) { 12294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mCurrentRow == null) 12304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new InflateException("orphant end row tag"); 12314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mRightEdgeKey != null) { 12324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey.markAsRightEdge(mParams); 12334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 12344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka addEdgeSpace(mParams.mHorizontalEdgesPadding, row); 12364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY += row.mRowHeight; 12374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentRow = null; 12384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mTopEdge = false; 12394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endKey(Key key) { 12424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.onAddKey(key); 12434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mLeftEdge) { 12444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka key.markAsLeftEdge(mParams); 12454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = false; 12464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mTopEdge) { 12484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka key.markAsTopEdge(mParams); 12494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = key; 12514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endKeyboard() { 12544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // nothing to do here. 12554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void addEdgeSpace(float width, Row row) { 12584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka row.advanceXPos(width); 12594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = false; 12604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 12614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static float getDimensionOrFraction(TypedArray a, int index, int base, 12644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka float defValue) { 12654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue value = a.peekValue(index); 12664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (value == null) 12674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isFractionValue(value)) { 12694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getFraction(index, base, base, defValue); 12704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (isDimensionValue(value)) { 12714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getDimension(index, defValue); 12724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static int getEnumValue(TypedArray a, int index, int defValue) { 12774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue value = a.peekValue(index); 12784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (value == null) 12794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isIntegerValue(value)) { 12814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getInt(index, defValue); 12824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isFractionValue(TypedValue v) { 12874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_FRACTION; 12884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isDimensionValue(TypedValue v) { 12914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_DIMENSION; 12924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isIntegerValue(TypedValue v) { 12954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; 12964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isStringValue(TypedValue v) { 12994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_STRING; 13004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 13024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static String textAttr(String value, String name) { 13034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return value != null ? String.format(" %s=%s", name, value) : ""; 13044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 13064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static String booleanAttr(TypedArray a, int index, String name) { 13074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.hasValue(index) 13084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka ? String.format(" %s=%s", name, a.getBoolean(index, false)) : ""; 13094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13115a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka} 1312