MainKeyboardView.java revision ac78633be28e8990fc3b3a8de192c80966e746e3
15f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/* 25f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project 35f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 45f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 55f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * you may not use this file except in compliance with the License. 65f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * You may obtain a copy of the License at 75f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 85f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 95f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * See the License for the specific language governing permissions and 145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * limitations under the License. 155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 19d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaokaimport android.animation.AnimatorInflater; 2031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaokaimport android.animation.ObjectAnimator; 215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.Context; 225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.pm.PackageManager; 2327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport android.content.res.Resources; 244112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.content.res.TypedArray; 256dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport android.graphics.Canvas; 2622b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaokaimport android.graphics.Paint; 274112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.Paint.Align; 28bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaokaimport android.graphics.Typeface; 294112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.drawable.Drawable; 305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.os.Message; 3115d4793911fa305e0a58aced925961e948582979satokimport android.text.TextUtils; 325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.AttributeSet; 335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.Log; 345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.LayoutInflater; 355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.MotionEvent; 365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.View; 375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.ViewConfiguration; 38b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaokaimport android.view.ViewGroup; 39f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.widget.PopupWindow; 415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 44f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; 452321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.TimerProxy; 4699906b3fc2dcb447aafdd43dda0c4551513b293eTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.SuddenJumpingTouchEventHandler; 474daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport com.android.inputmethod.latin.Constants; 486dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinIME; 4915d4793911fa305e0a58aced925961e948582979satokimport com.android.inputmethod.latin.LatinImeLogger; 505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.StaticInnerHandlerWrapper; 5227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport com.android.inputmethod.latin.StringUtils; 533bf57a5624679a20db26df912077a53b9f90ad36Tadashi G. Takaokaimport com.android.inputmethod.latin.SubtypeLocale; 546dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport com.android.inputmethod.latin.Utils; 5515d4793911fa305e0a58aced925961e948582979satokimport com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; 56c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 576b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport java.util.Locale; 605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap; 615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/** 635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements. 645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @attr ref R.styleable#KeyboardView_keyHysteresisDistance 665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @attr ref R.styleable#KeyboardView_verticalCorrection 675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @attr ref R.styleable#KeyboardView_popupLayout 685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 69c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokapublic class MainKeyboardView extends KeyboardView implements PointerTracker.KeyEventHandler, 70c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka SuddenJumpingTouchEventHandler.ProcessMotionEvent { 71c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka private static final String TAG = MainKeyboardView.class.getSimpleName(); 725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 73d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge // TODO: Kill process when the usability study mode was changed. 74d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy; 75d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge 76bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /** Listener for {@link KeyboardActionListener}. */ 77bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private KeyboardActionListener mKeyboardActionListener; 78bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka 79bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /* Space key and its icons */ 804112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Key mSpaceKey; 814112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Drawable mSpaceIcon; 82bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw language name on spacebar. 8331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private final int mLanguageOnSpacebarFinalAlpha; 8431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; 85bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mNeedsToDisplayLanguage; 86fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka private boolean mHasMultipleEnabledIMEsOrSubtypes; 874daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; 884112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final float mSpacebarTextRatio; 894112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private float mSpacebarTextSize; 904112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextColor; 914112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextShadowColor; 92bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // The minimum x-scale to fit the language name on spacebar. 93bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f; 94bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw auto correction LED on spacebar. 95bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mAutoCorrectionSpacebarLedOn; 96bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final boolean mAutoCorrectionSpacebarLedEnabled; 97bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final Drawable mAutoCorrectionSpacebarLedIcon; 98bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private static final int SPACE_LED_LENGTH_PERCENT = 80; 9915d4793911fa305e0a58aced925961e948582979satok 10073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka // Stuff to draw altCodeWhileTyping keys. 10131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; 10231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; 1034daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; 10473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 1052affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka // More keys keyboard 1069d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private PopupWindow mMoreKeysWindow; 1079d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private MoreKeysPanel mMoreKeysPanel; 1089d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private int mMoreKeysPanelPointerTrackerId; 1099d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache = 1109d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka new WeakHashMap<Key, MoreKeysPanel>(); 1112affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint; 1125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 113160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka private final PointerTrackerParams mPointerTrackerParams; 114bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final SuddenJumpingTouchEventHandler mTouchScreenRegulator; 1155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 116bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka protected KeyDetector mKeyDetector; 11706b7c256b1992f93aab0e2cdb90f57718f0631fdTadashi G. Takaoka private boolean mHasDistinctMultitouch; 1185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private int mOldPointerCount = 1; 119e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mOldKey; 1205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 121160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka private final KeyTimerHandler mKeyTimerHandler; 1225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 123c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka private static class KeyTimerHandler extends StaticInnerHandlerWrapper<MainKeyboardView> 1242321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka implements TimerProxy { 12527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_TYPING_STATE_EXPIRED = 0; 126f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_REPEAT_KEY = 1; 127f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_LONGPRESS_KEY = 2; 1280ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka private static final int MSG_DOUBLE_TAP = 3; 1295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 130a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka private final KeyTimerParams mParams; 1315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 132c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka public KeyTimerHandler(MainKeyboardView outerInstance, KeyTimerParams params) { 1335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(outerInstance); 134a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mParams = params; 1355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 1385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void handleMessage(Message msg) { 139c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 1405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 1415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka switch (msg.what) { 14227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka case MSG_TYPING_STATE_EXPIRED: 14327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 14427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka break; 1455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_REPEAT_KEY: 1468a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key currentKey = tracker.getKey(); 1478a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (currentKey != null && currentKey.mCode == msg.arg1) { 1488a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka tracker.onRegisterKey(currentKey); 1498a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka startKeyRepeatTimer(tracker, mParams.mKeyRepeatInterval); 1508a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 1515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 1525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_LONGPRESS_KEY: 153a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka if (tracker != null) { 1542affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka keyboardView.openMoreKeysKeyboardIfRequired(tracker.getKey(), tracker); 155a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } else { 156a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1); 157a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 1585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 1595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 16232c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka private void startKeyRepeatTimer(PointerTracker tracker, long delay) { 1638a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key key = tracker.getKey(); 1648a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (key == null) return; 1658a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, key.mCode, 0, tracker), delay); 16632c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka } 16732c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka 1682321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 169a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startKeyRepeatTimer(PointerTracker tracker) { 17032c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka startKeyRepeatTimer(tracker, mParams.mKeyRepeatStartTimeout); 1715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelKeyRepeatTimer() { 1745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_REPEAT_KEY); 1755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1770d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka // TODO: Suppress layout changes in key repeat mode 1785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInKeyRepeat() { 1790d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka return hasMessages(MSG_REPEAT_KEY); 1805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1822321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 183a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(int code) { 18498b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka cancelLongPressTimer(); 185a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka final int delay; 186a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka switch (code) { 187a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka case Keyboard.CODE_SHIFT: 18840e9012276b1df9be8c1a9069eaeb16027549a85Tadashi G. Takaoka delay = mParams.mLongPressShiftKeyTimeout; 189a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka break; 190a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka default: 191a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka delay = 0; 192a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka break; 193a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 194a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka if (delay > 0) { 195a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, code, 0), delay); 196a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 197a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 198a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka 199a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 200a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public void startLongPressTimer(PointerTracker tracker) { 201a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka cancelLongPressTimer(); 2027b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (tracker == null) { 2037b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka return; 2047b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } 2057b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka final Key key = tracker.getKey(); 2067b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka final int delay; 2077b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka switch (key.mCode) { 2087b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka case Keyboard.CODE_SHIFT: 2097b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka delay = mParams.mLongPressShiftKeyTimeout; 2107b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka break; 2117b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka default: 2127b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (KeyboardSwitcher.getInstance().isInMomentarySwitchState()) { 2137b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka // We use longer timeout for sliding finger input started from the symbols 2147b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka // mode key. 2157b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka delay = mParams.mLongPressKeyTimeout * 3; 2167b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } else { 2177b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka delay = mParams.mLongPressKeyTimeout; 218a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 2197b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka break; 2207b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } 2217b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (delay > 0) { 2227b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); 223a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 2245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2262321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 22798b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer() { 2285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_LONGPRESS_KEY); 2295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 231d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, 23245213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final ObjectAnimator animatorToStart) { 23345213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka float startFraction = 0.0f; 23445213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka if (animatorToCancel.isStarted()) { 235b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka animatorToCancel.cancel(); 23645213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka startFraction = 1.0f - animatorToCancel.getAnimatedFraction(); 237b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 23845213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final long startTime = (long)(animatorToStart.getDuration() * startFraction); 23945213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.start(); 24045213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.setCurrentPlayTime(startTime); 241b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 242b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka 243d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeinAnimation(final MainKeyboardView keyboardView) { 244d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator, 245d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeinAnimator); 246d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 247d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 248d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeoutAnimation(final MainKeyboardView keyboardView) { 249d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeinAnimator, 250d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator); 251d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 252d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 2532321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 254d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka public void startTypingStateTimer(Key typedKey) { 255d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { 256d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 257d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 258d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 25973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final boolean isTyping = isTypingState(); 260f1678ba8024606349bc184cfeaead2be059f7b5bTadashi G. Takaoka removeMessages(MSG_TYPING_STATE_EXPIRED); 261d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 262d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 263d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka // When user hits the space or the enter key, just cancel the while-typing timer. 264d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final int typedCode = typedKey.mCode; 265d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka if (typedCode == Keyboard.CODE_SPACE || typedCode == Keyboard.CODE_ENTER) { 266d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 267d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 268d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 269d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 27073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka sendMessageDelayed( 27173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka obtainMessage(MSG_TYPING_STATE_EXPIRED), mParams.mIgnoreAltCodeKeyTimeout); 27273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (isTyping) { 27373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return; 27473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 275d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka startWhileTypingFadeoutAnimation(keyboardView); 27693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 27793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 27893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 27973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { 28073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return hasMessages(MSG_TYPING_STATE_EXPIRED); 28193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 28293246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 28393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 2840ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer() { 2850ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP), 2865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka ViewConfiguration.getDoubleTapTimeout()); 2875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2890ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 290beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer() { 291beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka removeMessages(MSG_DOUBLE_TAP); 292beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka } 293beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 294beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 2950ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout() { 2960ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka return hasMessages(MSG_DOUBLE_TAP); 2975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 298c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 299c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka @Override 3000ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelKeyTimers() { 3010ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyRepeatTimer(); 3020ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelLongPressTimer(); 303c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 304c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 3050ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelAllMessages() { 3060ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyTimers(); 307c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 308c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 309c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 310160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka public static class PointerTrackerParams { 311160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka public final boolean mSlidingKeyInputEnabled; 312160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka public final int mTouchNoiseThresholdTime; 313160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka public final float mTouchNoiseThresholdDistance; 314160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 315160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); 316160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 317160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka private PointerTrackerParams() { 318160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mSlidingKeyInputEnabled = false; 319160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mTouchNoiseThresholdTime =0; 320160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mTouchNoiseThresholdDistance = 0; 321160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 322160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 323c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka public PointerTrackerParams(TypedArray mainKeyboardViewAttr) { 324c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mSlidingKeyInputEnabled = mainKeyboardViewAttr.getBoolean( 325c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_slidingKeyInputEnable, false); 326c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mTouchNoiseThresholdTime = mainKeyboardViewAttr.getInt( 327c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdTime, 0); 328c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mTouchNoiseThresholdDistance = mainKeyboardViewAttr.getDimension( 329c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0); 330a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 331a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 332a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka 333a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka static class KeyTimerParams { 334a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public final int mKeyRepeatStartTimeout; 335a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public final int mKeyRepeatInterval; 336a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public final int mLongPressKeyTimeout; 337a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka public final int mLongPressShiftKeyTimeout; 33873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public final int mIgnoreAltCodeKeyTimeout; 339a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka 340c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka public KeyTimerParams(TypedArray mainKeyboardViewAttr) { 341c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt( 342c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0); 343c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mKeyRepeatInterval = mainKeyboardViewAttr.getInt( 344c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatInterval, 0); 345c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mLongPressKeyTimeout = mainKeyboardViewAttr.getInt( 346c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_longPressKeyTimeout, 0); 347c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mLongPressShiftKeyTimeout = mainKeyboardViewAttr.getInt( 348c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_longPressShiftKeyTimeout, 0); 349c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( 350c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); 351160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 352160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 353160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 354c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka public MainKeyboardView(Context context, AttributeSet attrs) { 355c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka this(context, attrs, R.attr.mainKeyboardViewStyle); 3565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 358c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka public MainKeyboardView(Context context, AttributeSet attrs, int defStyle) { 3595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(context, attrs, defStyle); 3605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 361c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this); 362c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 3635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mHasDistinctMultitouch = context.getPackageManager() 3645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); 365918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Resources res = getResources(); 366d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka final boolean needsPhantomSuddenMoveEventHack = Boolean.parseBoolean( 367918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka Utils.getDeviceOverrideValue(res, 368d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka R.array.phantom_sudden_move_event_device_list, "false")); 36962b8dddb6ddb057555a1665759f9cf197e480c9fTadashi G. Takaoka PointerTracker.init(mHasDistinctMultitouch, needsPhantomSuddenMoveEventHack); 37022b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 3714112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 372c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView); 3734112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedEnabled = a.getBoolean( 374c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false); 3754112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedIcon = a.getDrawable( 376c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedIcon); 377c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mSpacebarTextRatio = a.getFraction(R.styleable.MainKeyboardView_spacebarTextRatio, 3784112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1000, 1000, 1) / 1000.0f; 379c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mSpacebarTextColor = a.getColor(R.styleable.MainKeyboardView_spacebarTextColor, 0); 3804112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mSpacebarTextShadowColor = a.getColor( 381c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextShadowColor, 0); 38231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarFinalAlpha = a.getInt( 383c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha, 3844daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang Constants.Color.ALPHA_OPAQUE); 385d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka final int languageOnSpacebarFadeoutAnimatorResId = a.getResourceId( 386c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0); 38773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeoutAnimatorResId = a.getResourceId( 388c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0); 38973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeinAnimatorResId = a.getResourceId( 390c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); 391160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 392a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka final KeyTimerParams keyTimerParams = new KeyTimerParams(a); 393160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mPointerTrackerParams = new PointerTrackerParams(a); 394160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 395160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka final float keyHysteresisDistance = a.getDimension( 396c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistance, 0); 397160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka mKeyDetector = new KeyDetector(keyHysteresisDistance); 398a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mKeyTimerHandler = new KeyTimerHandler(this, keyTimerParams); 3992affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka mConfigShowMoreKeysKeyboardAtTouchedPoint = a.getBoolean( 400c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false); 4014112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka a.recycle(); 402160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 403160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka PointerTracker.setParameters(mPointerTrackerParams); 4044c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka 40531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator( 40631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka languageOnSpacebarFadeoutAnimatorResId, this); 40731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator( 40831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeoutAnimatorResId, this); 40931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator( 41031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeinAnimatorResId, this); 41131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 41231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 41331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator loadObjectAnimator(int resId, Object target) { 41431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (resId == 0) return null; 41531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator( 41631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka getContext(), resId); 417d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator != null) { 41831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.setTarget(target); 41973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 42031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return animator; 42131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 42273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 42331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka // Getter/setter methods for {@link ObjectAnimator}. 42431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getLanguageOnSpacebarAnimAlpha() { 42531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mLanguageOnSpacebarAnimAlpha; 426d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka } 427d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka 42831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public void setLanguageOnSpacebarAnimAlpha(int alpha) { 42931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = alpha; 43031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka invalidateKey(mSpaceKey); 43131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 43231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 43331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getAltCodeKeyWhileTypingAnimAlpha() { 43431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mAltCodeKeyWhileTypingAnimAlpha; 43531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 43631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 43731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public void setAltCodeKeyWhileTypingAnimAlpha(int alpha) { 43831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingAnimAlpha = alpha; 43931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka updateAltCodeKeyWhileTyping(); 4405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4425a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka public void setKeyboardActionListener(KeyboardActionListener listener) { 4435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyboardActionListener = listener; 4445c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.setKeyboardActionListener(listener); 4455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 4485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns the {@link KeyboardActionListener} object. 4495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return the listener attached to this keyboard 4505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 4510efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 4520efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener() { 4535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mKeyboardActionListener; 4545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 456bb4be5444b845655c0eb80bcfbb66f93603802eaTadashi G. Takaoka @Override 4570efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyDetector getKeyDetector() { 4580efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyDetector; 4590efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 4600efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 4610efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 462f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy() { 463f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka return this; 464f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 465f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 466f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka @Override 4670efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public TimerProxy getTimerProxy() { 4680efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyTimerHandler; 4690efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 4700efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 4715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 4725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Attaches a keyboard to this view. The keyboard can be switched at any time and the 4735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * view will re-layout itself to accommodate the keyboard. 4745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see Keyboard 4755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see #getKeyboard() 4765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param keyboard the keyboard to display in this view 4775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 4785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 4795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void setKeyboard(Keyboard keyboard) { 4808a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka // Remove any pending messages, except dismissing preview and key repeat. 4818a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka mKeyTimerHandler.cancelLongPressTimer(); 4825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.setKeyboard(keyboard); 4835a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyDetector.setKeyboard( 4845a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); 4858335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setKeyDetector(mKeyDetector); 486c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka mTouchScreenRegulator.setKeyboard(keyboard); 4879d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanelCache.clear(); 4884112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 4894112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE); 4901f2d0aa6c9b343848ee51e5bc13ccaaadf3ba4feTadashi G. Takaoka mSpaceIcon = (mSpaceKey != null) 4914daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; 4924112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; 4934112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mSpacebarTextSize = keyHeight * mSpacebarTextRatio; 49448a7681e064ae259b840f0e757da2d716043d893Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 495c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_setKeyboard(keyboard); 49648a7681e064ae259b840f0e757da2d716043d893Kurt Partridge } 497f147794fd41491a3383e6aca6d49007f58124068alanv 498f147794fd41491a3383e6aca6d49007f58124068alanv // This always needs to be set since the accessibility state can 499f147794fd41491a3383e6aca6d49007f58124068alanv // potentially change without the keyboard being set again. 500f147794fd41491a3383e6aca6d49007f58124068alanv AccessibleKeyboardViewProxy.getInstance().setKeyboard(keyboard); 5015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5038335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 5048335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka public void setMainDictionaryAvailability(boolean mainDictionaryAvailable) { 5058335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable); 5068335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 5078335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 5088335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka public void setGestureHandlingEnabledByUser(boolean gestureHandlingEnabledByUser) { 5098335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser); 5100657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka } 5110657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka 5125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 5135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns whether the device has distinct multi-touch panel. 5145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return true if the device has distinct multi-touch panel. 5155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 5165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean hasDistinctMultitouch() { 5175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mHasDistinctMultitouch; 5185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 52006b7c256b1992f93aab0e2cdb90f57718f0631fdTadashi G. Takaoka public void setDistinctMultitouch(boolean hasDistinctMultitouch) { 52106b7c256b1992f93aab0e2cdb90f57718f0631fdTadashi G. Takaoka mHasDistinctMultitouch = hasDistinctMultitouch; 52206b7c256b1992f93aab0e2cdb90f57718f0631fdTadashi G. Takaoka } 52306b7c256b1992f93aab0e2cdb90f57718f0631fdTadashi G. Takaoka 5245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 5254331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge protected void onAttachedToWindow() { 5264331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge super.onAttachedToWindow(); 5274331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // Notify the research logger that the keyboard view has been attached. This is needed 5284331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // to properly show the splash screen, which requires that the window token of the 5294331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // KeyboardView be non-null. 5304331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 531c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow(); 5324331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 5334331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 5344331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge 5354331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge @Override 5365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelAllMessages() { 537f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelAllMessages(); 5385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.cancelAllMessages(); 5395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5412affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka private boolean openMoreKeysKeyboardIfRequired(Key parentKey, PointerTracker tracker) { 5425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Check if we have a popup layout specified first. 5439d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysLayout == 0) { 5445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 5455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 54763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka // Check if we are already displaying popup panel. 5489d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysPanel != null) 54963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return false; 5505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (parentKey == null) 5515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 55263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return onLongPress(parentKey, tracker); 5535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5559d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka // This default implementation returns a more keys panel. 5569d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka protected MoreKeysPanel onCreateMoreKeysPanel(Key parentKey) { 5579d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (parentKey.mMoreKeys == null) 5585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return null; 5595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5609d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka final View container = LayoutInflater.from(getContext()).inflate(mMoreKeysLayout, null); 5615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (container == null) 5625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka throw new NullPointerException(); 5635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5642affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka final MoreKeysKeyboardView moreKeysKeyboardView = 5652affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); 5667ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder(container, parentKey, this) 5677ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka .build(); 5682affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); 569b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 5705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5712affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka return moreKeysKeyboardView; 5725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 5752affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka * Called when a key is long pressed. By default this will open more keys keyboard associated 5765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * with this key. 5775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param parentKey the key that was long pressed 5785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param tracker the pointer tracker which pressed the parent key 5795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return true if the long press is handled, false otherwise. Subclasses should call the 5805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * method on the base class if the subclass doesn't wish to handle the call. 5815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 5825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka protected boolean onLongPress(Key parentKey, PointerTracker tracker) { 5839bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 584c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_onLongPress(); 5859bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 5866dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka final int primaryCode = parentKey.mCode; 587e491be6e8690ffb8359887838fa12d5873346be5Tadashi G. Takaoka if (parentKey.hasEmbeddedMoreKey()) { 588ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka final int embeddedCode = parentKey.mMoreKeys[0].mCode; 5893708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka tracker.onLongPressed(); 590e491be6e8690ffb8359887838fa12d5873346be5Tadashi G. Takaoka invokeCodeInput(embeddedCode); 5913708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka invokeReleaseKey(primaryCode); 592a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode); 5933708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka return true; 5943708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka } 59581d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka if (primaryCode == Keyboard.CODE_SPACE || primaryCode == Keyboard.CODE_LANGUAGE_SWITCH) { 5963708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka // Long pressing the space key invokes IME switcher dialog. 5973708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { 5986dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 59942e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka invokeReleaseKey(primaryCode); 60042e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka return true; 6016dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6026dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 60317dc10724bf0db04d0a4bfb2b8be0739ad9e60c6Tadashi G. Takaoka return openMoreKeysPanel(parentKey, tracker); 6046dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6056dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 60642e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka private boolean invokeCustomRequest(int code) { 6072a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka return mKeyboardActionListener.onCustomRequest(code); 60842e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka } 60942e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka 61042e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka private void invokeCodeInput(int primaryCode) { 611ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka mKeyboardActionListener.onCodeInput( 612ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka primaryCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 61342e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka } 61442e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka 61542e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka private void invokeReleaseKey(int primaryCode) { 6162a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mKeyboardActionListener.onReleaseKey(primaryCode, false); 6176dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6186dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 6199d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private boolean openMoreKeysPanel(Key parentKey, PointerTracker tracker) { 6209d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka MoreKeysPanel moreKeysPanel = mMoreKeysPanelCache.get(parentKey); 6219d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (moreKeysPanel == null) { 6229d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka moreKeysPanel = onCreateMoreKeysPanel(parentKey); 6239d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (moreKeysPanel == null) 6245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 6259d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanelCache.put(parentKey, moreKeysPanel); 6265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6279d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysWindow == null) { 6289d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysWindow = new PopupWindow(getContext()); 6299d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysWindow.setBackgroundDrawable(null); 6302affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka mMoreKeysWindow.setAnimationStyle(R.style.MoreKeysKeyboardAnimation); 6315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6329d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanel = moreKeysPanel; 6339d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanelPointerTrackerId = tracker.mPointerId; 63463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 6357ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !parentKey.noKeyPreview(); 6367ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually horizontally aligned with the center of the parent key. 6377ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more 6387ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // keys keyboard is placed at the touch point of the parent key. 6397ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled) 6407ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka ? tracker.getLastX() 641f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka : parentKey.mX + parentKey.mWidth / 2; 6427ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually vertically aligned with the top edge of the parent key 6437ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically 6447ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // aligned with the bottom edge of the visible part of the key preview. 6457ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int pointY = parentKey.mY + (keyPreviewEnabled 6467ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka ? mKeyPreviewDrawParams.mPreviewVisibleOffset 6477ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka : -parentKey.mVerticalGap); 6489d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka moreKeysPanel.showMoreKeysPanel( 6492a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka this, this, pointX, pointY, mMoreKeysWindow, mKeyboardActionListener); 6509d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(tracker.getLastX()); 6519d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(tracker.getLastY()); 652e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaoka tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); 6531b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dimEntireKeyboard(true); 6545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 6555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 6589d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysPanel != null) { 65963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return true; 66063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } else { 6615c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return PointerTracker.isAnyInSlidingKeyInput(); 6625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public int getPointerCount() { 6665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mOldPointerCount; 6675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 6705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean onTouchEvent(MotionEvent me) { 67146286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka if (getKeyboard() == null) { 67246286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka return false; 67346286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka } 674c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka return mTouchScreenRegulator.onTouchEvent(me); 675c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 676c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 677c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka @Override 678c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka public boolean processMotionEvent(MotionEvent me) { 679f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final boolean nonDistinctMultitouch = !mHasDistinctMultitouch; 6805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int action = me.getActionMasked(); 6815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int pointerCount = me.getPointerCount(); 6825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int oldPointerCount = mOldPointerCount; 6835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mOldPointerCount = pointerCount; 6845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 6865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // If the device does not have distinct multi-touch support panel, ignore all multi-touch 6875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // events except a transition from/to single-touch. 688f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) { 6895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 6905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final long eventTime = me.getEventTime(); 6935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int index = me.getActionIndex(); 6945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int id = me.getPointerId(index); 69563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka final int x, y; 6969d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysPanel != null && id == mMoreKeysPanelPointerTrackerId) { 6979d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka x = mMoreKeysPanel.translateX((int)me.getX(index)); 6989d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka y = mMoreKeysPanel.translateY((int)me.getY(index)); 69963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } else { 70063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka x = (int)me.getX(index); 70163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka y = (int)me.getY(index); 7025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 703d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge if (ENABLE_USABILITY_STUDY_LOG) { 704d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final String eventTag; 705d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge switch (action) { 706d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge case MotionEvent.ACTION_UP: 707d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge eventTag = "[Up]"; 708d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge break; 709d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge case MotionEvent.ACTION_DOWN: 710d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge eventTag = "[Down]"; 711d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge break; 712d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge case MotionEvent.ACTION_POINTER_UP: 713d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge eventTag = "[PointerUp]"; 714d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge break; 715d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge case MotionEvent.ACTION_POINTER_DOWN: 716d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge eventTag = "[PointerDown]"; 717d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge break; 718d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge case MotionEvent.ACTION_MOVE: // Skip this as being logged below 719d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge eventTag = ""; 720d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge break; 721d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge default: 722d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge eventTag = "[Action" + action + "]"; 723d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge break; 724d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 725d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge if (!TextUtils.isEmpty(eventTag)) { 726d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final float size = me.getSize(index); 727d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final float pressure = me.getPressure(index); 728d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge UsabilityStudyLogUtils.getInstance().write( 729d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge eventTag + eventTime + "," + id + "," + x + "," + y + "," 730d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge + size + "," + pressure); 731d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 732d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 733c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 734c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_processMotionEvent(me, action, eventTime, index, id, 7359bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge x, y); 73615d4793911fa305e0a58aced925961e948582979satok } 7375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 738f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (mKeyTimerHandler.isInKeyRepeat()) { 739e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 7405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Key repeating timer will be canceled if 2 or more keys are in action, and current 7415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // event (UP or DOWN) is non-modifier key. 7425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount > 1 && !tracker.isModifier()) { 743f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelKeyRepeatTimer(); 7445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Up event will pass through. 7465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 7495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Translate mutli-touch event to single-touch events on the device that has no distinct 7505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // multi-touch panel. 751f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch) { 7525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Use only main (id=0) pointer tracker. 753e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 7545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount == 1 && oldPointerCount == 2) { 7555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Multi-touch to single touch transition. 7565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send a down event for the latest pointer if the key is different from the 7575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // previous key. 758e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key newKey = tracker.getKeyOn(x, y); 759e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (mOldKey != newKey) { 7600efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka tracker.onDownEvent(x, y, eventTime, this); 7615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (action == MotionEvent.ACTION_UP) 762906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka tracker.onUpEvent(x, y, eventTime); 7635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 2 && oldPointerCount == 1) { 7655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Single-touch to multi-touch transition. 7665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send an up event for the last pointer. 7675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int lastX = tracker.getLastX(); 7685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int lastY = tracker.getLastY(); 769e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka mOldKey = tracker.getKeyOn(lastX, lastY); 770906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka tracker.onUpEvent(lastX, lastY, eventTime); 7715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 1 && oldPointerCount == 1) { 7728ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 7735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 7745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount 7755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka + " (old " + oldPointerCount + ")"); 7765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 7785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (action == MotionEvent.ACTION_MOVE) { 7815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka for (int i = 0; i < pointerCount; i++) { 782d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final int pointerId = me.getPointerId(i); 783e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker( 784d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge pointerId, this); 78563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka final int px, py; 7863314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka final MotionEvent motionEvent; 7879d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysPanel != null 7889d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka && tracker.mPointerId == mMoreKeysPanelPointerTrackerId) { 7899d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka px = mMoreKeysPanel.translateX((int)me.getX(i)); 7909d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka py = mMoreKeysPanel.translateY((int)me.getY(i)); 7913314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka motionEvent = null; 79263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } else { 79363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka px = (int)me.getX(i); 79463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka py = (int)me.getY(i); 7953314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka motionEvent = me; 79663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 7973314d38dafc0b9670e695a194c74950c4ebf2b3dTadashi G. Takaoka tracker.onMoveEvent(px, py, eventTime, motionEvent); 798d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge if (ENABLE_USABILITY_STUDY_LOG) { 799d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final float pointerSize = me.getSize(i); 800d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final float pointerPressure = me.getPressure(i); 801d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge UsabilityStudyLogUtils.getInstance().write("[Move]" + eventTime + "," 802d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge + pointerId + "," + px + "," + py + "," 803d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge + pointerSize + "," + pointerPressure); 804d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 805c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 806c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_processMotionEvent(me, action, eventTime, 8079bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge i, pointerId, px, py); 80815d4793911fa305e0a58aced925961e948582979satok } 8095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 811e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 812e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 8135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 8155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 8165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 8185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 8195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void closing() { 8205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.closing(); 8219d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka dismissMoreKeysPanel(); 8229d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanelCache.clear(); 8235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 8259ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka @Override 8269d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public boolean dismissMoreKeysPanel() { 8279d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysWindow != null && mMoreKeysWindow.isShowing()) { 8289d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysWindow.dismiss(); 8299d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanel = null; 8309d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanelPointerTrackerId = -1; 8311b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dimEntireKeyboard(false); 8325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 8335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 8355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 837586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette /** 838c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka * Receives hover events from the input framework. 839586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * 840586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @param event The motion event to be dispatched. 841586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @return {@code true} if the event was handled by the view, {@code false} 842586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * otherwise 843586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette */ 844c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka @Override 845586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette public boolean dispatchHoverEvent(MotionEvent event) { 8465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 847e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 848586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker); 8495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 851586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette // Reflection doesn't support calling superclass methods. 8525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 8535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 85422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 8555afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka public void updateShortcutKey(boolean available) { 8567bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 8577bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka if (keyboard == null) return; 8587bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka final Key shortcutKey = keyboard.getKey(Keyboard.CODE_SHORTCUT); 8597bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka if (shortcutKey == null) return; 8607bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka shortcutKey.setEnabled(available); 8617bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka invalidateKey(shortcutKey); 8625afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka } 8635afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka 86473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka private void updateAltCodeKeyWhileTyping() { 86573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 86673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (keyboard == null) return; 86773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka for (final Key key : keyboard.mAltCodeKeysWhileTyping) { 86873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka invalidateKey(key); 86973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 87073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 87173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 872dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka public void startDisplayLanguageOnSpacebar(boolean subtypeChanged, 873fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka boolean needsToDisplayLanguage, boolean hasMultipleEnabledIMEsOrSubtypes) { 8744112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mNeedsToDisplayLanguage = needsToDisplayLanguage; 875fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; 876fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; 877d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator == null) { 878aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka mNeedsToDisplayLanguage = false; 8794c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } else { 880dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka if (subtypeChanged && needsToDisplayLanguage) { 8814daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); 88231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (animator.isStarted()) { 88331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.cancel(); 88431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 885d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka animator.start(); 886dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } else { 88731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (!animator.isStarted()) { 88831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha; 88931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 890dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } 8914c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } 8924112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 8934112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 8944112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 8954112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka public void updateAutoCorrectionState(boolean isAutoCorrection) { 8964112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka if (!mAutoCorrectionSpacebarLedEnabled) return; 8974112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedOn = isAutoCorrection; 8984112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 89922b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 90022b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 90122b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka @Override 902f9521c6f378e3f2aa13d9e382ae13708e3ae6317Tadashi G. Takaoka protected void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint, KeyDrawParams params) { 9036bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.altCodeWhileTyping() && key.isEnabled()) { 90473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha; 90573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 9064112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka if (key.mCode == Keyboard.CODE_SPACE) { 907bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawSpacebar(key, canvas, paint); 9084112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Whether space key needs to show the "..." popup hint for special purposes 909fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) { 910bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 9114112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 91281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } else if (key.mCode == Keyboard.CODE_LANGUAGE_SWITCH) { 91381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 914fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 915b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka } else { 916b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 91722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 91822b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 9194112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 920bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka private boolean fitsTextIntoWidth(final int width, String text, Paint paint) { 921bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(1.0f); 922bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final float textWidth = getLabelWidth(text, paint); 923bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka if (textWidth < width) return true; 924bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 925bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final float scaleX = width / textWidth; 926bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) return false; 927bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 928bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(scaleX); 929bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return getLabelWidth(text, paint) < width; 930bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 931bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 932bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Layout language name on spacebar. 933bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka private String layoutLanguageOnSpacebar(Paint paint, InputMethodSubtype subtype, 934bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final int width) { 935bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Choose appropriate language name to fit into the width. 936bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka String text = getFullDisplayName(subtype, getResources()); 937bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka if (fitsTextIntoWidth(width, text, paint)) { 938bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return text; 939bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 940bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 941bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka text = getMiddleDisplayName(subtype); 942bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka if (fitsTextIntoWidth(width, text, paint)) { 943bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return text; 9444112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9454112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 946bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka text = getShortDisplayName(subtype); 947bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka if (fitsTextIntoWidth(width, text, paint)) { 948bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return text; 9494112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9504112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 951bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return ""; 9524112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9534112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 954bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private void drawSpacebar(Key key, Canvas canvas, Paint paint) { 955bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka final int width = key.mWidth; 956b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final int height = key.mHeight; 9574112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 958f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka // If input language are explicitly selected. 959bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mNeedsToDisplayLanguage) { 960bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextAlign(Align.CENTER); 961bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTypeface(Typeface.DEFAULT); 962bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextSize(mSpacebarTextSize); 963bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final InputMethodSubtype subtype = getKeyboard().mId.mSubtype; 964bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final String language = layoutLanguageOnSpacebar(paint, subtype, width); 9654112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw language text with shadow 9664112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float descent = paint.descent(); 9674112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float textHeight = -paint.ascent() + descent; 968b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final float baseline = height / 2 + textHeight / 2; 969aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextShadowColor); 97031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 9714112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent - 1, paint); 972aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextColor); 97331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 9744112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent, paint); 9754112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9764112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 9774112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw the spacebar icon at the bottom 978bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mAutoCorrectionSpacebarLedOn) { 9794112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; 9804112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); 9814112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 9824112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 983bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight); 9844112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } else if (mSpaceIcon != null) { 9854112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = mSpaceIcon.getIntrinsicWidth(); 9864112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mSpaceIcon.getIntrinsicHeight(); 9874112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 9884112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 989bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight); 9904112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9914112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 99227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 99327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // InputMethodSubtype's display name for spacebar text in its locale. 99427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // isAdditionalSubtype (T=true, F=false) 99527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // locale layout | Short Middle Full 99627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // ------ ------ - ---- --------- ---------------------- 99727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // en_US qwerty F En English English (US) exception 99827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // en_GB qwerty F En English English (UK) exception 99927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // fr azerty F Fr Français Français 100027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // fr_CA qwerty F Fr Français Français (Canada) 100127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // de qwertz F De Deutsch Deutsch 100227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // zz qwerty F QWERTY QWERTY 100327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // fr qwertz T Fr Français Français (QWERTZ) 100427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // de qwerty T De Deutsch Deutsch (QWERTY) 100527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // en_US azerty T En English English (US) (AZERTY) 100627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // zz azerty T AZERTY AZERTY 100727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 100827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's full display name in its locale. 100927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka static String getFullDisplayName(InputMethodSubtype subtype, Resources res) { 101027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 101127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype); 101227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 101327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 101427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return SubtypeLocale.getSubtypeDisplayName(subtype, res); 101527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 101627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 101727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's short display name in its locale. 101827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka static String getShortDisplayName(InputMethodSubtype subtype) { 101927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 102027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return ""; 102127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 102227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka final Locale locale = SubtypeLocale.getSubtypeLocale(subtype); 102327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return StringUtils.toTitleCase(locale.getLanguage(), locale); 102427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 102527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 102627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's middle display name in its locale. 102727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka static String getMiddleDisplayName(InputMethodSubtype subtype) { 102827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 102927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype); 103027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 103127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka final Locale locale = SubtypeLocale.getSubtypeLocale(subtype); 103227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale); 103327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 10345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka} 1035