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