Keyboard.java revision 7ef1dabd92a9dae042965cd10d08a2cd47455dcc
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 1577ef1dabd92a9dae042965cd10d08a2cd47455dccsatok mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(), 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 391411749a4baddc0fda7720deb6e4d67c1f1558cc5Tadashi G. Takaoka /** 3924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Keyboard Building helper. 3934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * 3944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * This class parses Keyboard XML file and eventually build a Keyboard. 3954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * The Keyboard XML file looks like: 3964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 3974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/keyboard.xml --< 3984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Keyboard keyboard_attributes*< 3994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Keyboard Content --< 4004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Row row_attributes*< 4014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Row Content --< 4024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Spacer horizontalGap="0.2in" /< 4044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >include keyboardLayout="@xml/other_keys"< 4054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Row< 4074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >include keyboardLayout="@xml/other_rows"< 4084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Keyboard< 4104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * The XML file which is included in other file must have >merge< as root element, 4124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * such as: 4134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/other_keys.xml --< 4154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >merge< 4164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/merge< 4194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * and 4214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- xml/other_rows.xml --< 4234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >merge< 4244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Row row_attributes*< 4254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key key_attributes* /< 4264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/Row< 4274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/merge< 4294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * You can also use switch-case-default tags to select Rows and Keys. 4314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >switch< 4334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case case_attribute*< 4344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Any valid tags at switch position --< 4354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >default< 4384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >!-- Any valid tags at switch position --< 4394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/default< 4404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/switch< 4414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * You can declare Key style and specify styles within Key tags. 4434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * <pre> 4444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >switch< 4454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case mode="email"< 4464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >key-style styleName="f1-key" parentStyle="modifier-key" 4474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * keyLabel=".com" 4484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * /< 4494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >case mode="url"< 4514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >key-style styleName="f1-key" parentStyle="modifier-key" 4524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * keyLabel="http://" 4534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * /< 4544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/case< 4554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >/switch< 4564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * ... 4574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * >Key keyStyle="shift-key" ... /< 4584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * </pre> 4594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 4604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Builder<KP extends Params> { 4627a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private static final String BUILDER_TAG = "Keyboard.Builder"; 4634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final boolean DEBUG = false; 4644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Keyboard XML Tags 4664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_KEYBOARD = "Keyboard"; 4674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_ROW = "Row"; 4684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_KEY = "Key"; 4694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_SPACER = "Spacer"; 4704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_INCLUDE = "include"; 4714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_MERGE = "merge"; 4724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_SWITCH = "switch"; 4734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_CASE = "case"; 4744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final String TAG_DEFAULT = "default"; 4754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static final String TAG_KEY_STYLE = "key-style"; 4764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int DEFAULT_KEYBOARD_COLUMNS = 10; 4784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int DEFAULT_KEYBOARD_ROWS = 4; 4794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final KP mParams; 4814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final Context mContext; 4824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka protected final Resources mResources; 4834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final DisplayMetrics mDisplayMetrics; 4844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private int mCurrentY = 0; 4864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Row mCurrentRow = null; 4874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean mLeftEdge; 4884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean mTopEdge; 4894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Key mRightEdgeKey = null; 4904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final KeyStyles mKeyStyles = new KeyStyles(); 4914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 4924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** 4934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate. 4944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * Some of the key size defaults can be overridden per row from what the {@link Keyboard} 4954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka * defines. 4964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka */ 4974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static class Row { 4984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyWidth enum constants 4994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_NOT_ENUM = 0; 5004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_FILL_RIGHT = -1; 5014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static final int KEYWIDTH_FILL_BOTH = -2; 5024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final Params mParams; 5044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Default width of a key in this row. */ 505a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka private float mDefaultKeyWidth; 5064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka /** Default height of a key in this row. */ 5074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public final int mRowHeight; 508b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka /** Default keyLabelFlags in this row. */ 509b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka private int mDefaultKeyLabelFlags; 5104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private final int mCurrentY; 5124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Will be updated by {@link Key}'s constructor. 5134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private float mCurrentX; 5144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Row(Resources res, Params params, XmlPullParser parser, int y) { 5164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams = params; 5174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 5184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard); 5194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRowHeight = (int)Builder.getDimensionOrFraction(keyboardAttr, 5204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_rowHeight, 5214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight, params.mDefaultRowHeight); 5224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardAttr.recycle(); 5234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser), 5244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 5254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mDefaultKeyWidth = Builder.getDimensionOrFraction(keyAttr, 5264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, 5274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth, params.mDefaultKeyWidth); 5284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttr.recycle(); 5294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 530b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka mDefaultKeyLabelFlags = 0; 5314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY = y; 5324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX = 0.0f; 5334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 535a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public float getDefaultKeyWidth() { 536a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka return mDefaultKeyWidth; 537a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 538a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 539a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public void setDefaultKeyWidth(float defaultKeyWidth) { 540a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka mDefaultKeyWidth = defaultKeyWidth; 541a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 542a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 543b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka public int getDefaultKeyLabelFlags() { 544b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka return mDefaultKeyLabelFlags; 545b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka } 546b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka 547b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka public void setDefaultKeyLabelFlags(int keyLabelFlags) { 548b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka mDefaultKeyLabelFlags = keyLabelFlags; 549b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka } 550b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka 5514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setXPos(float keyXPos) { 5524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX = keyXPos; 5534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void advanceXPos(float width) { 5564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentX += width; 5574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public int getKeyY() { 5604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentY; 5614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float getKeyX(TypedArray keyAttr) { 5644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthType = Builder.getEnumValue(keyAttr, 5654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 5664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (widthType == KEYWIDTH_FILL_BOTH) { 5674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillBoth, the key width should start right after the nearest 5684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // key on the left hand side. 5694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentX; 5704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 5724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardRightEdge = mParams.mOccupiedWidth 5734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - mParams.mHorizontalEdgesPadding; 5744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) { 5754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final float keyXPos = Builder.getDimensionOrFraction(keyAttr, 5764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0); 5774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (keyXPos < 0) { 5784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyXPos is negative, the actual x-coordinate will be 5794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyboardWidth + keyXPos. 5804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // keyXPos shouldn't be less than mCurrentX because drawable area for this 5814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // key starts at mCurrentX. Or, this key will overlaps the adjacent key on 5824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // its left hand side. 5834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return Math.max(keyXPos + keyboardRightEdge, mCurrentX); 5844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 5854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return keyXPos + mParams.mHorizontalEdgesPadding; 5864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return mCurrentX; 5894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 5904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 591a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka public float getKeyWidth(TypedArray keyAttr) { 592a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka return getKeyWidth(keyAttr, mCurrentX); 593a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 594a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka 5954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public float getKeyWidth(TypedArray keyAttr, float keyXPos) { 5964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int widthType = Builder.getEnumValue(keyAttr, 5974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM); 5984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka switch (widthType) { 5994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka case KEYWIDTH_FILL_RIGHT: 6004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka case KEYWIDTH_FILL_BOTH: 6014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardRightEdge = 6024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding; 6034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillRight, the actual key width will be determined to fill 6044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // out the area up to the right edge of the keyboard. 6054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If keyWidth is fillBoth, the actual key width will be determined to fill out 6064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the area between the nearest key on the left hand side and the right edge of 6074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the keyboard. 6084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return keyboardRightEdge - keyXPos; 6094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka default: // KEYWIDTH_NOT_ENUM 6104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return Builder.getDimensionOrFraction(keyAttr, 6114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, 6124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mBaseWidth, mDefaultKeyWidth); 6134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Builder(Context context, KP params) { 6184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mContext = context; 6194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Resources res = context.getResources(); 6204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mResources = res; 6214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mDisplayMetrics = res.getDisplayMetrics(); 6224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams = params; 6244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka setTouchPositionCorrectionData(context, params); 626e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok setAdditionalProximityChars(context, params); 6274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width); 6294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height); 6304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static void setTouchPositionCorrectionData(Context context, Params params) { 6334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 6344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka null, R.styleable.Keyboard, R.attr.keyboardStyle, 0); 6354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mThemeId = a.getInt(R.styleable.Keyboard_themeId, 0); 6364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int resourceId = a.getResourceId( 6374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_touchPositionCorrectionData, 0); 6384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 6394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (resourceId == 0) { 6404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (LatinImeLogger.sDBG) 6417a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.e(BUILDER_TAG, "touchPositionCorrectionData is not defined"); 6424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return; 6434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String[] data = context.getResources().getStringArray(resourceId); 6464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mTouchPositionCorrection.load(data); 6474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 649e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok private static void setAdditionalProximityChars(Context context, Params params) { 650e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final String[] additionalChars = 651e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok context.getResources().getStringArray(R.array.additional_proximitychars); 652e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok int currentPrimaryIndex = 0; 653e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok for (int i = 0; i < additionalChars.length; ++i) { 654e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final String additionalChar = additionalChars[i]; 655e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok if (TextUtils.isEmpty(additionalChar)) { 656e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex = 0; 657e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } else if (currentPrimaryIndex == 0) { 658e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex = additionalChar.charAt(0); 659e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok params.mAdditionalProximityChars.put( 660e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok currentPrimaryIndex, new ArrayList<Integer>()); 661e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } else if (currentPrimaryIndex != 0) { 662e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok final int c = additionalChar.charAt(0); 663e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok params.mAdditionalProximityChars.get(currentPrimaryIndex).add(c); 664e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 665e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 666e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok } 667e05b3f4b3a57dcf99ade35bfbc1e1cdc3c3e476csatok 66809f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka public void setAutoGenerate(KeyboardSet.KeysCache keysCache) { 66909f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka mParams.mKeysCache = keysCache; 67009f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka } 67109f8b126e532ca2ac6bbe00c0d78bf03e44b78a2Tadashi G. Takaoka 6724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Builder<KP> load(int xmlId, KeyboardId id) { 6734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mId = id; 6744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final XmlResourceParser parser = mResources.getXml(xmlId); 6754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 6764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboard(parser); 6774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (XmlPullParserException e) { 6787a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.w(BUILDER_TAG, "keyboard XML parse error: " + e); 6794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new IllegalArgumentException(e); 6804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } catch (IOException e) { 6817a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.w(BUILDER_TAG, "keyboard XML parse error: " + e); 6824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new RuntimeException(e); 6834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 6844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parser.close(); 6854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return this; 6874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public void setTouchPositionCorrectionEnabled(boolean enabled) { 6904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mTouchPositionCorrection.setEnabled(enabled); 6914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public Keyboard build() { 6944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return new Keyboard(mParams); 6954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 6964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 6977a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private int mIndent; 6987a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private static final String SPACES = " "; 6997a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7007a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private static String spaces(int count) { 7017a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka return (count < SPACES.length()) ? SPACES.substring(0, count) : SPACES; 7027a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 7037a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7047a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void startTag(String format, Object ... args) { 7057a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args)); 7067a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 7077a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7087a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void endTag(String format, Object ... args) { 7097a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.d(BUILDER_TAG, String.format(spaces(mIndent-- * 2) + format, args)); 7107a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 7117a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7127a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void startEndTag(String format, Object ... args) { 7137a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args)); 7147a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka mIndent--; 7157a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 7167a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 7174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboard(XmlPullParser parser) 7184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 7197a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s> %s", TAG_KEYBOARD, mParams.mId); 7204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 7214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 7224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 7234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 7244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEYBOARD.equals(tag)) { 7254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardAttributes(parser); 7264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka startKeyboard(); 7274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, false); 7284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 7294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 7304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEYBOARD); 7314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboardAttributes(XmlPullParser parser) { 7374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int displayWidth = mDisplayMetrics.widthPixels; 7384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray keyboardAttr = mContext.obtainStyledAttributes( 7394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Xml.asAttributeSet(parser), R.styleable.Keyboard, R.attr.keyboardStyle, 7404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.style.Keyboard); 7414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), 7424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 7434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 7444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int displayHeight = mDisplayMetrics.heightPixels; 7454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int keyboardHeight = (int)keyboardAttr.getDimension( 7464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardHeight, displayHeight / 2); 7474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, 7484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2); 7494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr, 7504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2); 7514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (minKeyboardHeight < 0) { 7524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Specified fraction was negative, so it should be calculated against display 7534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // width. 7544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr, 7554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2); 7564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Params params = mParams; 7584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Keyboard height will not exceed maxKeyboardHeight and will not be less than 7594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // minKeyboardHeight. 7604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mOccupiedHeight = Math.max( 7614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); 7624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mOccupiedWidth = params.mId.mWidth; 7634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr, 7644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0); 7654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr, 7664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0); 7674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr, 7684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_keyboardHorizontalEdgesPadding, 7694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.mOccupiedWidth, 0); 7704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2 7724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - params.mHorizontalCenterPadding; 7734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr, 7744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, 7754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS); 7764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr, 7774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0); 7784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr, 7794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0); 7804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding 7814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka - params.mBottomPadding + params.mVerticalGap; 7824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr, 7834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_rowHeight, params.mBaseHeight, 7844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mBaseHeight / DEFAULT_KEYBOARD_ROWS); 7854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mMoreKeysTemplate = keyboardAttr.getResourceId( 7874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_moreKeysTemplate, 0); 7882affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka params.mMaxMoreKeysKeyboardColumn = keyAttr.getInt( 7894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key_maxMoreKeysColumn, 5); 7904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka params.mIconsSet.loadIcons(keyboardAttr); 7924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 7934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttr.recycle(); 7944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyboardAttr.recycle(); 7954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 7974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 7984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyboardContent(XmlPullParser parser, boolean skip) 7994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 8014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 8024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 8034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_ROW.equals(tag)) { 8054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka Row row = parseRowAttributes(parser); 8067a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s>%s", TAG_ROW, skip ? " skipped" : ""); 8077a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (!skip) { 8084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka startRow(row); 8097a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 8104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 8114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_INCLUDE.equals(tag)) { 8124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeKeyboardContent(parser, skip); 8134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SWITCH.equals(tag)) { 8144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchKeyboardContent(parser, skip); 8154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyStyle(parser, skip); 8174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_ROW); 8194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 8214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8227a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) endTag("</%s>", tag); 8234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEYBOARD.equals(tag)) { 8244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKeyboard(); 8254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) 8274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || TAG_MERGE.equals(tag)) { 8284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW); 8314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private Row parseRowAttributes(XmlPullParser parser) throws XmlPullParserException { 8374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 8384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard); 8394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 8404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (a.hasValue(R.styleable.Keyboard_horizontalGap)) 8414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap"); 8424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (a.hasValue(R.styleable.Keyboard_verticalGap)) 8434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap"); 8444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return new Row(mResources, mParams, parser, mCurrentY); 8454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 8464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 8474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseRowContent(XmlPullParser parser, Row row, boolean skip) 8514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 8534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 8544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 8554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_KEY.equals(tag)) { 8574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKey(parser, row, skip); 8584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SPACER.equals(tag)) { 8594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSpacer(parser, row, skip); 8604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_INCLUDE.equals(tag)) { 8614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeRowContent(parser, row, skip); 8624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_SWITCH.equals(tag)) { 8634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchRowContent(parser, row, skip); 8644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_KEY_STYLE.equals(tag)) { 8654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyStyle(parser, skip); 8664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); 8684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 8704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 8717a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) endTag("</%s>", tag); 8724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_ROW.equals(tag)) { 8737a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (!skip) { 8744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endRow(row); 8757a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 8764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag) 8784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || TAG_MERGE.equals(tag)) { 8794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 8804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); 8824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 8864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 8874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKey(XmlPullParser parser, Row row, boolean skip) 8884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 8894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 8904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY, parser); 8917a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY); 8924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 8934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Key key = new Key(mResources, mParams, row, parser, mKeyStyles); 8947a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) { 8957a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY, 8967a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka (key.isEnabled() ? "" : " disabled"), key, 8977a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka Arrays.toString(key.mMoreKeys)); 8987a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 8994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY, parser); 9004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKey(key); 9014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSpacer(XmlPullParser parser, Row row, boolean skip) 9054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 9074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_SPACER, parser); 9087a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startEndTag("<%s /> skipped", TAG_SPACER); 9094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 9104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final Key.Spacer spacer = new Key.Spacer( 9114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mResources, mParams, row, parser, mKeyStyles); 9127a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startEndTag("<%s />", TAG_SPACER); 9134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_SPACER, parser); 9144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka endKey(spacer); 9154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeKeyboardContent(XmlPullParser parser, boolean skip) 9194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeInternal(parser, null, skip); 9214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeRowContent(XmlPullParser parser, Row row, boolean skip) 9244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseIncludeInternal(parser, row, skip); 9264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseIncludeInternal(XmlPullParser parser, Row row, boolean skip) 9294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (skip) { 9314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); 9327a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startEndTag("</%s> skipped", TAG_INCLUDE); 9334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 934a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final AttributeSet attr = Xml.asAttributeSet(parser); 935a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final TypedArray keyboardAttr = mResources.obtainAttributes(attr, 9364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include); 937a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka final TypedArray keyAttr = mResources.obtainAttributes(attr, 938a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka R.styleable.Keyboard_Key); 9394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int keyboardLayout = 0; 940a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka float savedDefaultKeyWidth = 0; 941b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka int savedDefaultKeyLabelFlags = 0; 9424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 943a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka XmlParseUtils.checkAttributeExists(keyboardAttr, 9444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include_keyboardLayout, "keyboardLayout", 9454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TAG_INCLUDE, parser); 946a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyboardLayout = keyboardAttr.getResourceId( 9474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Include_keyboardLayout, 0); 948a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (row != null) { 949a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka savedDefaultKeyWidth = row.getDefaultKeyWidth(); 950b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka savedDefaultKeyLabelFlags = row.getDefaultKeyLabelFlags(); 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 } 959b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyLabelFlags)) { 960b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka // Override default key label flags. 961b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka row.setDefaultKeyLabelFlags( 962b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0) 963b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka | savedDefaultKeyLabelFlags); 964b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka } 965a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 9664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 967a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyboardAttr.recycle(); 968a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka keyAttr.recycle(); 9694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_INCLUDE, parser); 9727a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) { 9737a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka startEndTag("<%s keyboardLayout=%s />",TAG_INCLUDE, 9747a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka mResources.getResourceEntryName(keyboardLayout)); 9757a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 9764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout); 9774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 9784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseMerge(parserForInclude, row, skip); 9794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 980a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka if (row != null) { 981b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka // Restore default key width and key label flags. 982a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka row.setDefaultKeyWidth(savedDefaultKeyWidth); 983b03529aa0119d38054fe825156669c45f7a6c8c3Tadashi G. Takaoka row.setDefaultKeyLabelFlags(savedDefaultKeyLabelFlags); 984a1e370ee4fd033fae0f783d9120f6ab75d1ce711Tadashi G. Takaoka } 9854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parserForInclude.close(); 9864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 9894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 9904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseMerge(XmlPullParser parser, Row row, boolean skip) 9914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 9927a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s>", TAG_MERGE); 9934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 9944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 9954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 9964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 9974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_MERGE.equals(tag)) { 9984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 9994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, skip); 10004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 10024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 10044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.ParseException( 10064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka "Included keyboard layout must have <merge> root element", parser); 10074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchKeyboardContent(XmlPullParser parser, boolean skip) 10134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchInternal(parser, null, skip); 10154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchRowContent(XmlPullParser parser, Row row, boolean skip) 10184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseSwitchInternal(parser, row, skip); 10204e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip) 10234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10247a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s> %s", TAG_SWITCH, mParams.mId); 10254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka boolean selected = false; 10264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka int event; 10274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) { 10284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (event == XmlPullParser.START_TAG) { 10294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 10304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_CASE.equals(tag)) { 10314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka selected |= parseCase(parser, row, selected ? true : skip); 10324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (TAG_DEFAULT.equals(tag)) { 10334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka selected |= parseDefault(parser, row, selected ? true : skip); 10344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalStartTag(parser, TAG_KEY); 10364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (event == XmlPullParser.END_TAG) { 10384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final String tag = parser.getName(); 10394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (TAG_SWITCH.equals(tag)) { 10407a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) endTag("</%s>", TAG_SWITCH); 10414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka break; 10424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY); 10444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseCase(XmlPullParser parser, Row row, boolean skip) 10504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 10514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean selected = parseCaseCondition(parser); 10524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 10534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Processing Rows. 10544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, selected ? skip : true); 10554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 10564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // Processing Keys. 10574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, selected ? skip : true); 10584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return selected; 10604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 10614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseCaseCondition(XmlPullParser parser) { 10634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final KeyboardId id = mParams.mId; 10644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (id == null) 10654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 10664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 10674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser), 10684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case); 10694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 107083306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka final boolean keyboardSetElementMatched = matchTypedValue(a, 107183306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka R.styleable.Keyboard_Case_keyboardSetElement, id.mElementId, 107283306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka KeyboardId.elementIdToName(id.mElementId)); 10734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean modeMatched = matchTypedValue(a, 10744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode)); 107505bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka final boolean navigateNextMatched = matchBoolean(a, 107605bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka R.styleable.Keyboard_Case_navigateNext, id.navigateNext()); 107705bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka final boolean navigatePreviousMatched = matchBoolean(a, 107805bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka R.styleable.Keyboard_Case_navigatePrevious, id.navigatePrevious()); 10794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean passwordInputMatched = matchBoolean(a, 10804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_passwordInput, id.passwordInput()); 10814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean clobberSettingsKeyMatched = matchBoolean(a, 10824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_clobberSettingsKey, id.mClobberSettingsKey); 10834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean shortcutKeyEnabledMatched = matchBoolean(a, 10844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); 10854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean hasShortcutKeyMatched = matchBoolean(a, 10864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); 108781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka final boolean languageSwitchKeyEnabledMatched = matchBoolean(a, 108881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka R.styleable.Keyboard_Case_languageSwitchKeyEnabled, 108981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka id.mLanguageSwitchKeyEnabled); 10907a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka final boolean isMultiLineMatched = matchBoolean(a, 10917a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine()); 10924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean imeActionMatched = matchInteger(a, 10934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_imeAction, id.imeAction()); 10944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean localeCodeMatched = matchString(a, 10954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_localeCode, id.mLocale.toString()); 10964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean languageCodeMatched = matchString(a, 10974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage()); 10984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final boolean countryCodeMatched = matchString(a, 10994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry()); 110083306b914f36871f785677ca13e1ce8033774b79Tadashi G. Takaoka final boolean selected = keyboardSetElementMatched && modeMatched 110105bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka && navigateNextMatched && navigatePreviousMatched && passwordInputMatched 110297bde43740d8ba7f8aedde35d20621823140966cTadashi G. Takaoka && clobberSettingsKeyMatched && shortcutKeyEnabledMatched 110381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched 110481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && isMultiLineMatched && imeActionMatched && localeCodeMatched 110581d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && languageCodeMatched && countryCodeMatched; 11067a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 11077a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) { 110881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, 11097a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), 11107a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "keyboardSetElement"), 11117a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), 111205bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_imeAction), 111305bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka "imeAction"), 111405bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_navigateNext, 111505bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka "navigateNext"), 111605bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_navigatePrevious, 111705bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka "navigatePrevious"), 11187a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey, 11197a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "clobberSettingsKey"), 112005bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, 112105bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka "passwordInput"), 11227a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled, 11237a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "shortcutKeyEnabled"), 11247a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, 11257a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "hasShortcutKey"), 112681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_languageSwitchKeyEnabled, 112781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka "languageSwitchKeyEnabled"), 11287a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine, 11297a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "isMultiLine"), 11307a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), 11317a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "localeCode"), 11327a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), 11337a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "languageCode"), 11347a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), 11357a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka "countryCode"), 11367a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka selected ? "" : " skipped"); 11377a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return selected; 11404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 11414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka a.recycle(); 11424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchInteger(TypedArray a, int index, int value) { 11464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) || a.getInt(index, 0) == value; 11494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchBoolean(TypedArray a, int index, boolean value) { 11524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) || a.getBoolean(index, false) == value; 11554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchString(TypedArray a, int index, String value) { 11584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return !a.hasValue(index) 11614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka || stringArrayContains(a.getString(index).split("\\|"), value); 11624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean matchTypedValue(TypedArray a, int index, int intValue, 11654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka String strValue) { 11664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // If <case> does not have "index" attribute, that means this <case> is wild-card for 11674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // the attribute. 11684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue v = a.peekValue(index); 11694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (v == null) 11704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isIntegerValue(v)) { 11734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return intValue == a.getInt(index, 0); 11744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (isStringValue(v)) { 11754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return stringArrayContains(a.getString(index).split("\\|"), strValue); 11764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return false; 11784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean stringArrayContains(String[] array, String value) { 11814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka for (final String elem : array) { 11824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (elem.equals(value)) 11834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return false; 11864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private boolean parseDefault(XmlPullParser parser, Row row, boolean skip) 11894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throws XmlPullParserException, IOException { 11907a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) startTag("<%s>", TAG_DEFAULT); 11914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (row == null) { 11924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseKeyboardContent(parser, skip); 11934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else { 11944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka parseRowContent(parser, row, skip); 11954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return true; 11974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 11984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 11994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void parseKeyStyle(XmlPullParser parser, boolean skip) 12007a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka throws XmlPullParserException, IOException { 12014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser), 12024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_KeyStyle); 12034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser), 12044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka R.styleable.Keyboard_Key); 12054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka try { 12064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) 12074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE 12084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka + "/> needs styleName attribute", parser); 12097a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (DEBUG) { 12107a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka startEndTag("<%s styleName=%s />%s", TAG_KEY_STYLE, 12117a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName), 12127a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka skip ? " skipped" : ""); 12137a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (!skip) 12154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser); 12164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } finally { 12174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyStyleAttr.recycle(); 12184e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka keyAttrs.recycle(); 12194e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12207a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka XmlParseUtils.checkEndTag(TAG_KEY_STYLE, parser); 12214e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12224e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12234e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void startKeyboard() { 12244e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY += mParams.mTopPadding; 12254e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mTopEdge = true; 12264e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12274e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12284e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void startRow(Row row) { 12294e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka addEdgeSpace(mParams.mHorizontalEdgesPadding, row); 12304e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentRow = row; 12314e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = true; 12324e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 12334e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12344e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12354e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endRow(Row row) { 12364e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mCurrentRow == null) 12374e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka throw new InflateException("orphant end row tag"); 12384e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mRightEdgeKey != null) { 12394e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey.markAsRightEdge(mParams); 12404e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 12414e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12424e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka addEdgeSpace(mParams.mHorizontalEdgesPadding, row); 12434e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentY += row.mRowHeight; 12444e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mCurrentRow = null; 12454e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mTopEdge = false; 12464e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12474e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12484e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endKey(Key key) { 12494e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mParams.onAddKey(key); 12504e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mLeftEdge) { 12514e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka key.markAsLeftEdge(mParams); 12524e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = false; 12534e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12544e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (mTopEdge) { 12554e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka key.markAsTopEdge(mParams); 12564e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12574e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = key; 12584e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12594e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12604e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void endKeyboard() { 12614e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka // nothing to do here. 12624e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12634e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12644e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private void addEdgeSpace(float width, Row row) { 12654e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka row.advanceXPos(width); 12664e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mLeftEdge = false; 12674e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka mRightEdgeKey = null; 12684e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12694e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12704e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static float getDimensionOrFraction(TypedArray a, int index, int base, 12714e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka float defValue) { 12724e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue value = a.peekValue(index); 12734e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (value == null) 12744e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12754e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isFractionValue(value)) { 12764e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getFraction(index, base, base, defValue); 12774e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } else if (isDimensionValue(value)) { 12784e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getDimension(index, defValue); 12794e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12804e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12814e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12824e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12834e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka public static int getEnumValue(TypedArray a, int index, int defValue) { 12844e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka final TypedValue value = a.peekValue(index); 12854e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (value == null) 12864e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12874e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka if (isIntegerValue(value)) { 12884e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.getInt(index, defValue); 12894e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12904e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return defValue; 12914e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12924e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12934e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isFractionValue(TypedValue v) { 12944e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_FRACTION; 12954e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 12964e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 12974e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isDimensionValue(TypedValue v) { 12984e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_DIMENSION; 12994e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13004e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 13014e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isIntegerValue(TypedValue v) { 13024e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; 13034e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13044e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 13054e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static boolean isStringValue(TypedValue v) { 13064e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return v.type == TypedValue.TYPE_STRING; 13074e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13084e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 13094e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static String textAttr(String value, String name) { 13104e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return value != null ? String.format(" %s=%s", name, value) : ""; 13114e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13124e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka 13134e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka private static String booleanAttr(TypedArray a, int index, String name) { 13144e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka return a.hasValue(index) 13154e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka ? String.format(" %s=%s", name, a.getBoolean(index, false)) : ""; 13164e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13174e1dab8cfaad891fe041ed8d71893186c05cef71Tadashi G. Takaoka } 13185a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka} 1319