MainKeyboardView.java revision 915f348b35cb66ed9696a51c9250f9b25799fb82
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; 2213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport android.content.SharedPreferences; 235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.pm.PackageManager; 2427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport android.content.res.Resources; 254112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.content.res.TypedArray; 266dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport android.graphics.Canvas; 2722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaokaimport android.graphics.Paint; 284112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.Paint.Align; 29bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaokaimport android.graphics.Typeface; 304112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.drawable.Drawable; 315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.os.Message; 3272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaokaimport android.os.SystemClock; 3313ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport android.preference.PreferenceManager; 345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.AttributeSet; 355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.Log; 365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.LayoutInflater; 375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.MotionEvent; 385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.View; 395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.ViewConfiguration; 40b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaokaimport android.view.ViewGroup; 41f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 4515f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.ExternallyReferenced; 46f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; 472321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.TimerProxy; 4849d8af8a4e900f3c68c333aba7fde0a11fd368b1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyDrawParams; 49081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.TouchScreenRegulator; 504daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport com.android.inputmethod.latin.Constants; 51547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaokaimport com.android.inputmethod.latin.CoordinateUtils; 5213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport com.android.inputmethod.latin.DebugSettings; 536dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinIME; 5415d4793911fa305e0a58aced925961e948582979satokimport com.android.inputmethod.latin.LatinImeLogger; 555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 569879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils; 575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.StaticInnerHandlerWrapper; 5827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport com.android.inputmethod.latin.StringUtils; 593bf57a5624679a20db26df912077a53b9f90ad36Tadashi G. Takaokaimport com.android.inputmethod.latin.SubtypeLocale; 6015d4793911fa305e0a58aced925961e948582979satokimport com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; 61c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 626b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport java.util.Locale; 655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap; 665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/** 685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements. 695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 70dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedEnabled 71dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedIcon 72dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextRatio 73dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextColor 74dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextShadowColor 75dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha 76dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFadeoutAnimator 77dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator 78dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator 79dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyHysteresisDistance 80dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdTime 81dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdDistance 82dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_slidingKeyInputEnable 83dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatStartTimeout 84dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatInterval 85dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressKeyTimeout 86dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout 87dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout 88dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint 893623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping 903623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDetectFastMoveSpeedThreshold 913623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicThresholdDecayDuration 923623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdFrom 933623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdTo 943623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdFrom 953623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdTo 963623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureSamplingMinimumDistance 973623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionMinimumTime 983623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold 993623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration 1005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 101a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class MainKeyboardView extends KeyboardView implements PointerTracker.KeyEventHandler, 102081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaoka TouchScreenRegulator.ProcessMotionEvent { 103c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka private static final String TAG = MainKeyboardView.class.getSimpleName(); 1045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 105d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge // TODO: Kill process when the usability study mode was changed. 106d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy; 107d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge 108bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /** Listener for {@link KeyboardActionListener}. */ 109bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private KeyboardActionListener mKeyboardActionListener; 110bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka 111bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /* Space key and its icons */ 1124112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Key mSpaceKey; 1134112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Drawable mSpaceIcon; 114bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw language name on spacebar. 11531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private final int mLanguageOnSpacebarFinalAlpha; 11631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; 117bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mNeedsToDisplayLanguage; 118fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka private boolean mHasMultipleEnabledIMEsOrSubtypes; 1194daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; 1204112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final float mSpacebarTextRatio; 1214112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private float mSpacebarTextSize; 1224112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextColor; 1234112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextShadowColor; 124bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // The minimum x-scale to fit the language name on spacebar. 125bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f; 126bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw auto correction LED on spacebar. 127bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mAutoCorrectionSpacebarLedOn; 128bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final boolean mAutoCorrectionSpacebarLedEnabled; 129bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final Drawable mAutoCorrectionSpacebarLedIcon; 130bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private static final int SPACE_LED_LENGTH_PERCENT = 80; 13115d4793911fa305e0a58aced925961e948582979satok 13273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka // Stuff to draw altCodeWhileTyping keys. 13331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; 13431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; 1354daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; 13673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 1372affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka // More keys keyboard 1389d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache = 1399d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka new WeakHashMap<Key, MoreKeysPanel>(); 1402affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint; 1415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 142081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaoka private final TouchScreenRegulator mTouchScreenRegulator; 1435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 144bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka protected KeyDetector mKeyDetector; 14513ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka private final boolean mHasDistinctMultitouch; 1465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private int mOldPointerCount = 1; 147e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mOldKey; 1485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 149160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka private final KeyTimerHandler mKeyTimerHandler; 1505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 151a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka private static final class KeyTimerHandler extends StaticInnerHandlerWrapper<MainKeyboardView> 1522321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka implements TimerProxy { 15327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_TYPING_STATE_EXPIRED = 0; 154f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_REPEAT_KEY = 1; 155f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_LONGPRESS_KEY = 2; 1560ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka private static final int MSG_DOUBLE_TAP = 3; 15772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private static final int MSG_UPDATE_BATCH_INPUT = 4; 1585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1595509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mKeyRepeatStartTimeout; 1605509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mKeyRepeatInterval; 1615509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mLongPressKeyTimeout; 1625509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mLongPressShiftKeyTimeout; 1635509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mIgnoreAltCodeKeyTimeout; 16472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private final int mGestureRecognitionUpdateTime; 1655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1665509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public KeyTimerHandler(final MainKeyboardView outerInstance, 1675509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka final TypedArray mainKeyboardViewAttr) { 1685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(outerInstance); 1695509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 1705509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt( 1715509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0); 1725509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mKeyRepeatInterval = mainKeyboardViewAttr.getInt( 1735509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatInterval, 0); 1745509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mLongPressKeyTimeout = mainKeyboardViewAttr.getInt( 1755509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_longPressKeyTimeout, 0); 1765509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mLongPressShiftKeyTimeout = mainKeyboardViewAttr.getInt( 1775509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_longPressShiftKeyTimeout, 0); 1785509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( 1795509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); 18072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt( 18172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0); 1825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 185dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void handleMessage(final Message msg) { 186c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 1875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 1885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka switch (msg.what) { 18927e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka case MSG_TYPING_STATE_EXPIRED: 19027e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 19127e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka break; 1925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_REPEAT_KEY: 1938a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key currentKey = tracker.getKey(); 1948a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (currentKey != null && currentKey.mCode == msg.arg1) { 1958a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka tracker.onRegisterKey(currentKey); 1965509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka startKeyRepeatTimer(tracker, mKeyRepeatInterval); 1978a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 1985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 1995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_LONGPRESS_KEY: 200a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka if (tracker != null) { 2012affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka keyboardView.openMoreKeysKeyboardIfRequired(tracker.getKey(), tracker); 202a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } else { 203a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1); 204a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 2055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 20672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka case MSG_UPDATE_BATCH_INPUT: 20772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka tracker.updateBatchInputByTimer(SystemClock.uptimeMillis()); 20872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka startUpdateBatchInputTimer(tracker); 20972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka break; 2105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 213dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void startKeyRepeatTimer(final PointerTracker tracker, final long delay) { 2148a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key key = tracker.getKey(); 21520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (key == null) { 21620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 21720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 2188a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, key.mCode, 0, tracker), delay); 21932c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka } 22032c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka 2212321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 222dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startKeyRepeatTimer(final PointerTracker tracker) { 2235509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka startKeyRepeatTimer(tracker, mKeyRepeatStartTimeout); 2245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelKeyRepeatTimer() { 2275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_REPEAT_KEY); 2285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2300d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka // TODO: Suppress layout changes in key repeat mode 2315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInKeyRepeat() { 2320d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka return hasMessages(MSG_REPEAT_KEY); 2335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2352321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 236dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startLongPressTimer(final int code) { 23798b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka cancelLongPressTimer(); 238a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka final int delay; 239a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka switch (code) { 240240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHIFT: 2415509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka delay = mLongPressShiftKeyTimeout; 242a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka break; 243a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka default: 244a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka delay = 0; 245a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka break; 246a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 247a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka if (delay > 0) { 248a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, code, 0), delay); 249a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 250a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 251a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka 252a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 253dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startLongPressTimer(final PointerTracker tracker) { 254a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka cancelLongPressTimer(); 2557b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (tracker == null) { 2567b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka return; 2577b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } 2587b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka final Key key = tracker.getKey(); 2597b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka final int delay; 2607b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka switch (key.mCode) { 261240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHIFT: 2625509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka delay = mLongPressShiftKeyTimeout; 2637b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka break; 2647b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka default: 2657b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (KeyboardSwitcher.getInstance().isInMomentarySwitchState()) { 2667b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka // We use longer timeout for sliding finger input started from the symbols 2677b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka // mode key. 2685509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka delay = mLongPressKeyTimeout * 3; 2697b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } else { 2705509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka delay = mLongPressKeyTimeout; 271a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 2727b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka break; 2737b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } 2747b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (delay > 0) { 2757b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); 276a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 2775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2792321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 28098b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer() { 2815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_LONGPRESS_KEY); 2825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 284d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, 28545213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final ObjectAnimator animatorToStart) { 28645213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka float startFraction = 0.0f; 28745213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka if (animatorToCancel.isStarted()) { 288b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka animatorToCancel.cancel(); 28945213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka startFraction = 1.0f - animatorToCancel.getAnimatedFraction(); 290b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 29145213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final long startTime = (long)(animatorToStart.getDuration() * startFraction); 29245213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.start(); 29345213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.setCurrentPlayTime(startTime); 294b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 295b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka 296d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeinAnimation(final MainKeyboardView keyboardView) { 297d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator, 298d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeinAnimator); 299d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 300d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 301d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeoutAnimation(final MainKeyboardView keyboardView) { 302d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeinAnimator, 303d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator); 304d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 305d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 3062321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 307dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startTypingStateTimer(final Key typedKey) { 308d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { 309d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 310d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 311d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 31273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final boolean isTyping = isTypingState(); 313f1678ba8024606349bc184cfeaead2be059f7b5bTadashi G. Takaoka removeMessages(MSG_TYPING_STATE_EXPIRED); 314d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 315d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 316d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka // When user hits the space or the enter key, just cancel the while-typing timer. 317d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final int typedCode = typedKey.mCode; 318240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) { 319d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 320d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 321d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 322d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 32373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka sendMessageDelayed( 3245509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka obtainMessage(MSG_TYPING_STATE_EXPIRED), mIgnoreAltCodeKeyTimeout); 32573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (isTyping) { 32673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return; 32773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 328d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka startWhileTypingFadeoutAnimation(keyboardView); 32993246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 33093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 33193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 33273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { 33373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return hasMessages(MSG_TYPING_STATE_EXPIRED); 33493246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 33593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3369f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka @Override 3370ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer() { 3380ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP), 3395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka ViewConfiguration.getDoubleTapTimeout()); 3405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3420ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 343beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer() { 344beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka removeMessages(MSG_DOUBLE_TAP); 345beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka } 346beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 347beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 3480ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout() { 3490ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka return hasMessages(MSG_DOUBLE_TAP); 3505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 351c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 352c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka @Override 3530ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelKeyTimers() { 3540ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyRepeatTimer(); 3550ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelLongPressTimer(); 356c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 357c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 35872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 35972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(final PointerTracker tracker) { 36072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (mGestureRecognitionUpdateTime <= 0) { 36172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka return; 36272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 36372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 36472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_BATCH_INPUT, tracker), 36572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureRecognitionUpdateTime); 36672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 36772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 36872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 369915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka public void cancelUpdateBatchInputTimer(final PointerTracker tracker) { 370915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 371915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka } 372915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka 373915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka @Override 3742db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers() { 37572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT); 37672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 37772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 3780ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelAllMessages() { 3790ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyTimers(); 3802db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka cancelAllUpdateBatchInputTimers(); 381c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 382c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 383c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 384dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs) { 385c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka this(context, attrs, R.attr.mainKeyboardViewStyle); 3865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 388dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { 3895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(context, attrs, defStyle); 3905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 391081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaoka mTouchScreenRegulator = new TouchScreenRegulator(context, this); 392c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 39313ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 39413ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean forceNonDistinctMultitouch = prefs.getBoolean( 395a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false); 39613ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean hasDistinctMultitouch = context.getPackageManager() 3975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); 39813ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mHasDistinctMultitouch = hasDistinctMultitouch && !forceNonDistinctMultitouch; 399918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Resources res = getResources(); 400d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka final boolean needsPhantomSuddenMoveEventHack = Boolean.parseBoolean( 401fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka ResourceUtils.getDeviceOverrideValue( 402fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka res, R.array.phantom_sudden_move_event_device_list)); 40393b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka PointerTracker.init(needsPhantomSuddenMoveEventHack); 40422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 4054112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 406c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView); 4074112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedEnabled = a.getBoolean( 408c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false); 4094112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedIcon = a.getDrawable( 410c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedIcon); 411ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka mSpacebarTextRatio = a.getFraction( 412ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextRatio, 1, 1, 1.0f); 413c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka mSpacebarTextColor = a.getColor(R.styleable.MainKeyboardView_spacebarTextColor, 0); 4144112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mSpacebarTextShadowColor = a.getColor( 415c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextShadowColor, 0); 41631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarFinalAlpha = a.getInt( 417c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha, 4184daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang Constants.Color.ALPHA_OPAQUE); 419d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka final int languageOnSpacebarFadeoutAnimatorResId = a.getResourceId( 420c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0); 42173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeoutAnimatorResId = a.getResourceId( 422c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0); 42373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeinAnimatorResId = a.getResourceId( 424c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); 425160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 426160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka final float keyHysteresisDistance = a.getDimension( 427c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistance, 0); 428f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka final float keyHysteresisDistanceForSlidingModifier = a.getDimension( 429f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0); 430f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mKeyDetector = new KeyDetector( 431f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier); 4325509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mKeyTimerHandler = new KeyTimerHandler(this, a); 4332affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka mConfigShowMoreKeysKeyboardAtTouchedPoint = a.getBoolean( 434c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false); 4355509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka PointerTracker.setParameters(a); 4364112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka a.recycle(); 437160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 43831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator( 43931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka languageOnSpacebarFadeoutAnimatorResId, this); 44031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator( 44131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeoutAnimatorResId, this); 44231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator( 44331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeinAnimatorResId, this); 44431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 44531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 446dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private ObjectAnimator loadObjectAnimator(final int resId, final Object target) { 44720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (resId == 0) { 44820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return null; 44920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 45031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator( 45131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka getContext(), resId); 452d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator != null) { 45331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.setTarget(target); 45473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 45531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return animator; 45631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 45773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 45815f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 45931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getLanguageOnSpacebarAnimAlpha() { 46031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mLanguageOnSpacebarAnimAlpha; 461d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka } 462d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka 46315f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 464dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setLanguageOnSpacebarAnimAlpha(final int alpha) { 46531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = alpha; 46631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka invalidateKey(mSpaceKey); 46731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 46831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 46915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 47031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getAltCodeKeyWhileTypingAnimAlpha() { 47131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mAltCodeKeyWhileTypingAnimAlpha; 47231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 47331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 47415f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 475dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) { 47631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingAnimAlpha = alpha; 47731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka updateAltCodeKeyWhileTyping(); 4785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 480dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboardActionListener(final KeyboardActionListener listener) { 4815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyboardActionListener = listener; 4825c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.setKeyboardActionListener(listener); 4835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 4865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns the {@link KeyboardActionListener} object. 4875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return the listener attached to this keyboard 4885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 4890efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 4900efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener() { 4915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mKeyboardActionListener; 4925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 494bb4be5444b845655c0eb80bcfbb66f93603802eaTadashi G. Takaoka @Override 4950efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyDetector getKeyDetector() { 4960efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyDetector; 4970efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 4980efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 4990efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 500f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy() { 501f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka return this; 502f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 503f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 504f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka @Override 5050efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public TimerProxy getTimerProxy() { 5060efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyTimerHandler; 5070efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 5080efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 5095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 5105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Attaches a keyboard to this view. The keyboard can be switched at any time and the 5115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * view will re-layout itself to accommodate the keyboard. 5125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see Keyboard 5135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see #getKeyboard() 5145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param keyboard the keyboard to display in this view 5155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 5165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 517dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboard(final Keyboard keyboard) { 5188a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka // Remove any pending messages, except dismissing preview and key repeat. 5198a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka mKeyTimerHandler.cancelLongPressTimer(); 5205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.setKeyboard(keyboard); 5215a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyDetector.setKeyboard( 5225a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); 5238335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setKeyDetector(mKeyDetector); 524081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaoka mTouchScreenRegulator.setKeyboardGeometry(keyboard.mOccupiedWidth); 5259d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanelCache.clear(); 5264112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 527240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka mSpaceKey = keyboard.getKey(Constants.CODE_SPACE); 5281f2d0aa6c9b343848ee51e5bc13ccaaadf3ba4feTadashi G. Takaoka mSpaceIcon = (mSpaceKey != null) 5294daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; 5304112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; 5314112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mSpacebarTextSize = keyHeight * mSpacebarTextRatio; 53248a7681e064ae259b840f0e757da2d716043d893Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 533c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_setKeyboard(keyboard); 53448a7681e064ae259b840f0e757da2d716043d893Kurt Partridge } 535f147794fd41491a3383e6aca6d49007f58124068alanv 536f147794fd41491a3383e6aca6d49007f58124068alanv // This always needs to be set since the accessibility state can 537f147794fd41491a3383e6aca6d49007f58124068alanv // potentially change without the keyboard being set again. 538b6ca354431367b625daf9fff5fbe4b1f5ef996abKen Wakasa AccessibleKeyboardViewProxy.getInstance().setKeyboard(); 5395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5418335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 542dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 5438335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable); 5448335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 5458335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 546dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 5478335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser); 5480657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka } 5490657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka 5505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 5514331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge protected void onAttachedToWindow() { 5524331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge super.onAttachedToWindow(); 5534331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // Notify the research logger that the keyboard view has been attached. This is needed 5544331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // to properly show the splash screen, which requires that the window token of the 5554331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // KeyboardView be non-null. 5564331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 557c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow(this); 558c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 559c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 560c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka 561c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka @Override 562c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka protected void onDetachedFromWindow() { 563c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka super.onDetachedFromWindow(); 564c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka // Notify the research logger that the keyboard view has been detached. This is needed 565c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka // to invalidate the reference of {@link MainKeyboardView} to null. 566c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka if (ProductionFlag.IS_EXPERIMENTAL) { 567c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onDetachedFromWindow(); 5684331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 5694331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 5704331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge 5714331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge @Override 5725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelAllMessages() { 573f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelAllMessages(); 5745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.cancelAllMessages(); 5755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 577dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private boolean openMoreKeysKeyboardIfRequired(final Key parentKey, 578dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final PointerTracker tracker) { 5795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Check if we have a popup layout specified first. 5809d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysLayout == 0) { 5815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 5825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 58463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka // Check if we are already displaying popup panel. 58520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (mMoreKeysPanel != null) { 58663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return false; 58720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 58820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (parentKey == null) { 5895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 59020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 59163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return onLongPress(parentKey, tracker); 5925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5949d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka // This default implementation returns a more keys panel. 595dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka protected MoreKeysPanel onCreateMoreKeysPanel(final Key parentKey) { 59620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (parentKey.mMoreKeys == null) { 5975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return null; 59820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 5995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6009d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka final View container = LayoutInflater.from(getContext()).inflate(mMoreKeysLayout, null); 60120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (container == null) { 6025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka throw new NullPointerException(); 60320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 6045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6052affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka final MoreKeysKeyboardView moreKeysKeyboardView = 6062affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); 6077ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder(container, parentKey, this) 6087ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka .build(); 6092affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); 610b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 6115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6122affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka return moreKeysKeyboardView; 6135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 6162affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka * Called when a key is long pressed. By default this will open more keys keyboard associated 6175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * with this key. 6185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param parentKey the key that was long pressed 6195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param tracker the pointer tracker which pressed the parent key 6205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return true if the long press is handled, false otherwise. Subclasses should call the 6215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * method on the base class if the subclass doesn't wish to handle the call. 6225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 623dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka protected boolean onLongPress(final Key parentKey, final PointerTracker tracker) { 6249bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 625c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_onLongPress(); 6269bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 6276dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka final int primaryCode = parentKey.mCode; 628e491be6e8690ffb8359887838fa12d5873346be5Tadashi G. Takaoka if (parentKey.hasEmbeddedMoreKey()) { 629ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka final int embeddedCode = parentKey.mMoreKeys[0].mCode; 6303708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka tracker.onLongPressed(); 631e491be6e8690ffb8359887838fa12d5873346be5Tadashi G. Takaoka invokeCodeInput(embeddedCode); 6323708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka invokeReleaseKey(primaryCode); 633a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode); 6343708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka return true; 6353708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka } 636240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (primaryCode == Constants.CODE_SPACE || primaryCode == Constants.CODE_LANGUAGE_SWITCH) { 6373708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka // Long pressing the space key invokes IME switcher dialog. 6383708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { 6396dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 64042e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka invokeReleaseKey(primaryCode); 64142e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka return true; 6426dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6436dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 64417dc10724bf0db04d0a4bfb2b8be0739ad9e60c6Tadashi G. Takaoka return openMoreKeysPanel(parentKey, tracker); 6456dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6466dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 647dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private boolean invokeCustomRequest(final int code) { 6482a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka return mKeyboardActionListener.onCustomRequest(code); 64942e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka } 65042e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka 651dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void invokeCodeInput(final int primaryCode) { 652ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka mKeyboardActionListener.onCodeInput( 653ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka primaryCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 65442e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka } 65542e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka 656dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void invokeReleaseKey(final int primaryCode) { 6572a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mKeyboardActionListener.onReleaseKey(primaryCode, false); 6586dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6596dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 660dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private boolean openMoreKeysPanel(final Key parentKey, final PointerTracker tracker) { 6619d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka MoreKeysPanel moreKeysPanel = mMoreKeysPanelCache.get(parentKey); 6629d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (moreKeysPanel == null) { 6639d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka moreKeysPanel = onCreateMoreKeysPanel(parentKey); 66420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (moreKeysPanel == null) { 6655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 66620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 6679d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanelCache.put(parentKey, moreKeysPanel); 6685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 66963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 670547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 671547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.getLastCoordinates(lastCoords); 6727ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !parentKey.noKeyPreview(); 6737ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually horizontally aligned with the center of the parent key. 6747ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more 6757ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // keys keyboard is placed at the touch point of the parent key. 6767ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled) 677547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka ? CoordinateUtils.x(lastCoords) 678f44a01b40852dde2363a061cdc7df2ef4cb59aadTadashi G. Takaoka : parentKey.mX + parentKey.mWidth / 2; 6797ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually vertically aligned with the top edge of the parent key 6807ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically 6817ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // aligned with the bottom edge of the visible part of the key preview. 68229d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@code mPreviewVisibleOffset} has been set appropriately in 68329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@link KeyboardView#showKeyPreview(PointerTracker)}. 68429d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka final int pointY = parentKey.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset; 685fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); 686547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(CoordinateUtils.x(lastCoords)); 687547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(CoordinateUtils.y(lastCoords)); 688e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaoka tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); 689fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang dimEntireKeyboard(true /* dimmed */); 6905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 6915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 6949d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mMoreKeysPanel != null) { 69563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return true; 6965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 69720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return PointerTracker.isAnyInSlidingKeyInput(); 6985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public int getPointerCount() { 7015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mOldPointerCount; 7025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 705dc2ee7772402633817702e95c2a5b17f6dec03ebalanv public boolean dispatchTouchEvent(MotionEvent event) { 706dc2ee7772402633817702e95c2a5b17f6dec03ebalanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 707dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return AccessibleKeyboardViewProxy.getInstance().dispatchTouchEvent(event); 708dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 709dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return super.dispatchTouchEvent(event); 710dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 711dc2ee7772402633817702e95c2a5b17f6dec03ebalanv 712dc2ee7772402633817702e95c2a5b17f6dec03ebalanv @Override 713dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean onTouchEvent(final MotionEvent me) { 71446286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka if (getKeyboard() == null) { 71546286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka return false; 71646286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka } 717c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka return mTouchScreenRegulator.onTouchEvent(me); 718c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 719c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 720c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka @Override 721dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean processMotionEvent(final MotionEvent me) { 722f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final boolean nonDistinctMultitouch = !mHasDistinctMultitouch; 7235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int action = me.getActionMasked(); 7245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int pointerCount = me.getPointerCount(); 7255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int oldPointerCount = mOldPointerCount; 7265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mOldPointerCount = pointerCount; 7275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 7295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // If the device does not have distinct multi-touch support panel, ignore all multi-touch 7305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // events except a transition from/to single-touch. 731f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) { 7325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 7335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final long eventTime = me.getEventTime(); 7365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int index = me.getActionIndex(); 7375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int id = me.getPointerId(index); 73835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int x = (int)me.getX(index); 73935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int y = (int)me.getY(index); 74035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 741fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // TODO: This might be moved to the tracker.processMotionEvent() call below. 742fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka if (ENABLE_USABILITY_STUDY_LOG && action != MotionEvent.ACTION_MOVE) { 743fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka writeUsabilityStudyLog(me, action, eventTime, index, id, x, y); 744d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 745fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // TODO: This should be moved to the tracker.processMotionEvent() call below. 746fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // Currently the same "move" event is being logged twice. 747c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 748fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka ResearchLogger.mainKeyboardView_processMotionEvent( 749fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka me, action, eventTime, index, id, x, y); 75015d4793911fa305e0a58aced925961e948582979satok } 7515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 752f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (mKeyTimerHandler.isInKeyRepeat()) { 753e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 7545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Key repeating timer will be canceled if 2 or more keys are in action, and current 7555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // event (UP or DOWN) is non-modifier key. 7565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount > 1 && !tracker.isModifier()) { 757f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelKeyRepeatTimer(); 7585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Up event will pass through. 7605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 7635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Translate mutli-touch event to single-touch events on the device that has no distinct 7645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // multi-touch panel. 765f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch) { 7665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Use only main (id=0) pointer tracker. 767e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 7685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount == 1 && oldPointerCount == 2) { 7695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Multi-touch to single touch transition. 7705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send a down event for the latest pointer if the key is different from the 7715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // previous key. 772e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key newKey = tracker.getKeyOn(x, y); 773e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (mOldKey != newKey) { 7740efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka tracker.onDownEvent(x, y, eventTime, this); 775fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka if (action == MotionEvent.ACTION_UP) { 776906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka tracker.onUpEvent(x, y, eventTime); 777fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 7785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 2 && oldPointerCount == 1) { 7805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Single-touch to multi-touch transition. 7815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send an up event for the last pointer. 782547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 783547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka mOldKey = tracker.getKeyOn( 784547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords)); 785547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.onUpEvent( 786547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime); 7875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 1 && oldPointerCount == 1) { 7888ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 7895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 7905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount 7915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka + " (old " + oldPointerCount + ")"); 7925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 7945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (action == MotionEvent.ACTION_MOVE) { 7975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka for (int i = 0; i < pointerCount; i++) { 798d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final int pointerId = me.getPointerId(i); 799e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker( 800d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge pointerId, this); 80135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int px = (int)me.getX(i); 80235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int py = (int)me.getY(i); 80335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang tracker.onMoveEvent(px, py, eventTime, me); 804d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge if (ENABLE_USABILITY_STUDY_LOG) { 805fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka writeUsabilityStudyLog(me, action, eventTime, i, pointerId, px, py); 806d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 807c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 808fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka ResearchLogger.mainKeyboardView_processMotionEvent( 809fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka me, action, eventTime, i, pointerId, px, py); 81015d4793911fa305e0a58aced925961e948582979satok } 8115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 813e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 814e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 8155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 8175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 8185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 820fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka private static void writeUsabilityStudyLog(final MotionEvent me, final int action, 821fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final long eventTime, final int index, final int id, final int x, final int y) { 822fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final String eventTag; 823fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka switch (action) { 824fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_UP: 825fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Up]"; 826fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 827fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 828fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Down]"; 829fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 830fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 831fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[PointerUp]"; 832fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 833fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 834fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[PointerDown]"; 835fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 836fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 837fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Move]"; 838fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 839fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka default: 840fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Action" + action + "]"; 841fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 842fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 843fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final float size = me.getSize(index); 844fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final float pressure = me.getPressure(index); 845fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka UsabilityStudyLogUtils.getInstance().write( 846fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag + eventTime + "," + id + "," + x + "," + y + "," + size + "," + pressure); 847fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 848fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka 8495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 8505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void closing() { 8515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.closing(); 852ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang onCancelMoreKeysPanel(); 8539d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mMoreKeysPanelCache.clear(); 8545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 8569ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka @Override 857ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang public void onCancelMoreKeysPanel() { 858ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang super.onCancelMoreKeysPanel(); 859ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang PointerTracker.dismissAllMoreKeysPanels(); 860ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 861ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 862ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang @Override 863fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang public boolean onDismissMoreKeysPanel() { 864fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang dimEntireKeyboard(false /* dimmed */); 865fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang return super.onDismissMoreKeysPanel(); 8665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 868586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette /** 869c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka * Receives hover events from the input framework. 870586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * 871586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @param event The motion event to be dispatched. 872586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @return {@code true} if the event was handled by the view, {@code false} 873586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * otherwise 874586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette */ 875c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka @Override 876dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean dispatchHoverEvent(final MotionEvent event) { 8775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 878e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 879586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker); 8805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 882586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette // Reflection doesn't support calling superclass methods. 8835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 8845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 88522b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 886dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateShortcutKey(final boolean available) { 8877bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 88820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (keyboard == null) { 88920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 89020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 891240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT); 89220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (shortcutKey == null) { 89320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 89420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 8957bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka shortcutKey.setEnabled(available); 8967bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka invalidateKey(shortcutKey); 8975afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka } 8985afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka 89973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka private void updateAltCodeKeyWhileTyping() { 90073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 90120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (keyboard == null) { 90220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 90320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 90473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka for (final Key key : keyboard.mAltCodeKeysWhileTyping) { 90573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka invalidateKey(key); 90673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 90773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 90873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 909dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, 910dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final boolean needsToDisplayLanguage, final boolean hasMultipleEnabledIMEsOrSubtypes) { 9114112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mNeedsToDisplayLanguage = needsToDisplayLanguage; 912fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; 913fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; 914d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator == null) { 915aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka mNeedsToDisplayLanguage = false; 9164c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } else { 917dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka if (subtypeChanged && needsToDisplayLanguage) { 9184daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); 91931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (animator.isStarted()) { 92031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.cancel(); 92131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 922d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka animator.start(); 923dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } else { 92431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (!animator.isStarted()) { 92531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha; 92631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 927dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } 9284c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } 9294112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 9304112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9314112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 932dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateAutoCorrectionState(final boolean isAutoCorrection) { 93320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (!mAutoCorrectionSpacebarLedEnabled) { 93420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 93520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 9364112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedOn = isAutoCorrection; 9374112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 93822b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 93922b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 94022b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka @Override 941dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, 942dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final KeyDrawParams params) { 9436bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.altCodeWhileTyping() && key.isEnabled()) { 94473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha; 94573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 946240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (key.mCode == Constants.CODE_SPACE) { 947bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawSpacebar(key, canvas, paint); 9484112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Whether space key needs to show the "..." popup hint for special purposes 949fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) { 950bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 9514112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 952240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (key.mCode == Constants.CODE_LANGUAGE_SWITCH) { 95381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 954fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 955b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka } else { 956b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 95722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 95822b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 9594112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 960dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private boolean fitsTextIntoWidth(final int width, final String text, final Paint paint) { 961bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(1.0f); 962bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final float textWidth = getLabelWidth(text, paint); 96320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (textWidth < width) { 96420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return true; 96520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 966bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 967bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final float scaleX = width / textWidth; 96820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) { 96920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return false; 97020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 971bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 972bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(scaleX); 973bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return getLabelWidth(text, paint) < width; 974bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 975bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 976bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Layout language name on spacebar. 977dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private String layoutLanguageOnSpacebar(final Paint paint, final InputMethodSubtype subtype, 978bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final int width) { 979bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Choose appropriate language name to fit into the width. 98020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka final String fullText = getFullDisplayName(subtype, getResources()); 98120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, fullText, paint)) { 98220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return fullText; 983bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 984bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 98520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka final String middleText = getMiddleDisplayName(subtype); 98620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, middleText, paint)) { 98720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return middleText; 9884112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9894112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 99020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka final String shortText = getShortDisplayName(subtype); 99120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, shortText, paint)) { 99220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return shortText; 9934112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9944112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 995bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return ""; 9964112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 9974112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 998dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void drawSpacebar(final Key key, final Canvas canvas, final Paint paint) { 999bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka final int width = key.mWidth; 1000b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final int height = key.mHeight; 10014112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1002f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka // If input language are explicitly selected. 1003bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mNeedsToDisplayLanguage) { 1004bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextAlign(Align.CENTER); 1005bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTypeface(Typeface.DEFAULT); 1006bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextSize(mSpacebarTextSize); 1007bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final InputMethodSubtype subtype = getKeyboard().mId.mSubtype; 1008bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final String language = layoutLanguageOnSpacebar(paint, subtype, width); 10094112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw language text with shadow 10104112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float descent = paint.descent(); 10114112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float textHeight = -paint.ascent() + descent; 1012b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final float baseline = height / 2 + textHeight / 2; 1013aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextShadowColor); 101431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 10154112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent - 1, paint); 1016aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextColor); 101731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 10184112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent, paint); 10194112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 10204112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 10214112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw the spacebar icon at the bottom 1022bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mAutoCorrectionSpacebarLedOn) { 10234112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; 10244112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); 10254112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 10264112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1027bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight); 10284112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } else if (mSpaceIcon != null) { 10294112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = mSpaceIcon.getIntrinsicWidth(); 10304112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mSpaceIcon.getIntrinsicHeight(); 10314112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 10324112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1033bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight); 10344112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 10354112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 103627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 103727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // InputMethodSubtype's display name for spacebar text in its locale. 103827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // isAdditionalSubtype (T=true, F=false) 103976d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // locale layout | Short Middle Full 104076d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // ------ ------- - ---- --------- ---------------------- 104176d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // en_US qwerty F En English English (US) exception 104276d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // en_GB qwerty F En English English (UK) exception 104376d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // es_US spanish F Es Español Español (EE.UU.) exception 104476d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // fr azerty F Fr Français Français 104576d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // fr_CA qwerty F Fr Français Français (Canada) 104676d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // de qwertz F De Deutsch Deutsch 104776d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // zz qwerty F QWERTY QWERTY 104876d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // fr qwertz T Fr Français Français (QWERTZ) 104976d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // de qwerty T De Deutsch Deutsch (QWERTY) 105076d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // en_US azerty T En English English (US) (AZERTY) 105176d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // zz azerty T AZERTY AZERTY 105227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 105327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's full display name in its locale. 1054dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka static String getFullDisplayName(final InputMethodSubtype subtype, final Resources res) { 105527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 105627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype); 105727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 105827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 105927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return SubtypeLocale.getSubtypeDisplayName(subtype, res); 106027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 106127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 106227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's short display name in its locale. 1063dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka static String getShortDisplayName(final InputMethodSubtype subtype) { 106427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 106527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return ""; 106627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 106727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka final Locale locale = SubtypeLocale.getSubtypeLocale(subtype); 106827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return StringUtils.toTitleCase(locale.getLanguage(), locale); 106927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 107027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 107127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's middle display name in its locale. 1072dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka static String getMiddleDisplayName(final InputMethodSubtype subtype) { 107327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 107427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype); 107527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 107627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka final Locale locale = SubtypeLocale.getSubtypeLocale(subtype); 107727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale); 107827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 10795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka} 1080