MainKeyboardView.java revision c8814e20b7b0ed5f7e11292480e89152618dd862
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; 244112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.content.res.TypedArray; 256dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport android.graphics.Canvas; 26f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaokaimport android.graphics.Color; 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; 35375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport android.util.DisplayMetrics; 365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.Log; 37375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport android.util.SparseArray; 380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport android.util.TypedValue; 395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.LayoutInflater; 405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.MotionEvent; 415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.View; 425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.ViewConfiguration; 43b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaokaimport android.view.ViewGroup; 44f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 450e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport android.widget.TextView; 465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 4915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.ExternallyReferenced; 50f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; 512321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.TimerProxy; 52fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureFloatingPreviewText; 53fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureTrailsPreview; 5449d8af8a4e900f3c68c333aba7fde0a11fd368b1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyDrawParams; 550e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; 56375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PreviewPlacerView; 57fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.SlidingKeyInputPreview; 584daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport com.android.inputmethod.latin.Constants; 5915d4793911fa305e0a58aced925961e948582979satokimport com.android.inputmethod.latin.LatinImeLogger; 605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 61375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords; 62c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 63a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.DebugSettings; 64e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils; 65e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CoordinateUtils; 66e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper; 67a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaokaimport com.android.inputmethod.latin.utils.SubtypeLocaleUtils; 68ccf4a310279b13bbf0b6aac76a0878178c1dfb7dTadashi G. Takaokaimport com.android.inputmethod.latin.utils.TypefaceUtils; 694be6198cb73cc24e10834153c4e049644ed187e3Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.UsabilityStudyLogUtils; 70ccf4a310279b13bbf0b6aac76a0878178c1dfb7dTadashi G. Takaokaimport com.android.inputmethod.latin.utils.ViewLayoutUtils; 716b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap; 745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/** 765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements. 775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 78dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedEnabled 79dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedIcon 80dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextRatio 81dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextColor 82dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextShadowColor 83dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha 84dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFadeoutAnimator 85dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator 86dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator 87dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyHysteresisDistance 88dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdTime 89dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdDistance 90dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_slidingKeyInputEnable 91dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatStartTimeout 92dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatInterval 93dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressKeyTimeout 94dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout 95dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout 96375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLayout 970e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewOffset 980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewHeight 990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLingerTimeout 100d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardLayout 101f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_backgroundDimAlpha 102dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint 103375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureFloatingPreviewTextLingerTimeout 1043623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping 1053623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDetectFastMoveSpeedThreshold 1063623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicThresholdDecayDuration 1073623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdFrom 1083623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdTo 1093623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdFrom 1103623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdTo 1113623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureSamplingMinimumDistance 1123623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionMinimumTime 1133623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold 1143623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration 1155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 116a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class MainKeyboardView extends KeyboardView implements PointerTracker.KeyEventHandler, 117310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka PointerTracker.DrawingProxy, MoreKeysPanel.Controller { 118c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka private static final String TAG = MainKeyboardView.class.getSimpleName(); 1195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 120d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge // TODO: Kill process when the usability study mode was changed. 121d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy; 122d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge 123bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /** Listener for {@link KeyboardActionListener}. */ 124bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private KeyboardActionListener mKeyboardActionListener; 125bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka 126bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /* Space key and its icons */ 1274112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Key mSpaceKey; 1284112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Drawable mSpaceIcon; 129bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw language name on spacebar. 13031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private final int mLanguageOnSpacebarFinalAlpha; 13131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; 132bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mNeedsToDisplayLanguage; 133fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka private boolean mHasMultipleEnabledIMEsOrSubtypes; 1344daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; 1354112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final float mSpacebarTextRatio; 1364112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private float mSpacebarTextSize; 1374112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextColor; 1384112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextShadowColor; 139bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // The minimum x-scale to fit the language name on spacebar. 140bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f; 141bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw auto correction LED on spacebar. 142bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mAutoCorrectionSpacebarLedOn; 143bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final boolean mAutoCorrectionSpacebarLedEnabled; 144bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final Drawable mAutoCorrectionSpacebarLedIcon; 145bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private static final int SPACE_LED_LENGTH_PERCENT = 80; 14615d4793911fa305e0a58aced925961e948582979satok 14773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka // Stuff to draw altCodeWhileTyping keys. 14831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; 14931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; 1504daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; 15173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 152375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Preview placer view 153375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final PreviewPlacerView mPreviewPlacerView; 154375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final int[] mOriginCoords = CoordinateUtils.newInstance(); 155fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final GestureFloatingPreviewText mGestureFloatingPreviewText; 156fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final GestureTrailsPreview mGestureTrailsPreview; 157fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final SlidingKeyInputPreview mSlidingKeyInputPreview; 158375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 1590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Key preview 1600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int PREVIEW_ALPHA = 240; 161375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final int mKeyPreviewLayoutId; 1620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final int mKeyPreviewOffset; 1630e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final int mKeyPreviewHeight; 164375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final SparseArray<TextView> mKeyPreviewTexts = CollectionUtils.newSparseArray(); 1650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); 1660e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private boolean mShowKeyPreviewPopup = true; 1670e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private int mKeyPreviewLingerTimeout; 1680e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 1692affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka // More keys keyboard 170f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka private final Paint mBackgroundDimAlphaPaint = new Paint(); 171f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka private boolean mNeedsToDimEntireKeyboard; 172a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private final View mMoreKeysKeyboardContainer; 173a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = 174a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka CollectionUtils.newWeakHashMap(); 1752affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint; 176d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka // More keys panel (used by both more keys keyboard and more suggestions view) 177d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka // TODO: Consider extending to support multiple more keys panels 178d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka private MoreKeysPanel mMoreKeysPanel; 1795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 180375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Gesture floating preview text 181375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // TODO: Make this parameter customizable by user via settings. 182375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private int mGestureFloatingPreviewTextLingerTimeout; 183375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 184d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka private KeyDetector mKeyDetector; 18513ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka private final boolean mHasDistinctMultitouch; 1865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private int mOldPointerCount = 1; 187e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mOldKey; 1885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 189160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka private final KeyTimerHandler mKeyTimerHandler; 1905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 191a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka private static final class KeyTimerHandler extends StaticInnerHandlerWrapper<MainKeyboardView> 1922321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka implements TimerProxy { 19327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_TYPING_STATE_EXPIRED = 0; 194f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_REPEAT_KEY = 1; 195f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_LONGPRESS_KEY = 2; 1962a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka private static final int MSG_DOUBLE_TAP_SHIFT_KEY = 3; 19772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private static final int MSG_UPDATE_BATCH_INPUT = 4; 1985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1995509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mKeyRepeatStartTimeout; 2005509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mKeyRepeatInterval; 2015509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mIgnoreAltCodeKeyTimeout; 20272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private final int mGestureRecognitionUpdateTime; 2035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2045509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public KeyTimerHandler(final MainKeyboardView outerInstance, 2055509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka final TypedArray mainKeyboardViewAttr) { 2065f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(outerInstance); 2075509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 2085509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt( 2095509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0); 2105509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mKeyRepeatInterval = mainKeyboardViewAttr.getInt( 2115509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatInterval, 0); 2125509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( 2135509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); 21472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt( 21572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0); 2165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 219dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void handleMessage(final Message msg) { 220c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 22148d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka if (keyboardView == null) { 22248d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka return; 22348d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka } 2245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 2255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka switch (msg.what) { 22627e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka case MSG_TYPING_STATE_EXPIRED: 22727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 22827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka break; 2295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_REPEAT_KEY: 2308a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key currentKey = tracker.getKey(); 231f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final int code = msg.arg1; 232f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka if (currentKey != null && currentKey.mCode == code) { 2335509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka startKeyRepeatTimer(tracker, mKeyRepeatInterval); 234f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka startTypingStateTimer(currentKey); 235f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final KeyboardActionListener listener = 236f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka keyboardView.getKeyboardActionListener(); 2376455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka listener.onPressKey(code, true /* isRepeatKey */, true /* isSinglePointer */); 238f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onCodeInput(code, 239f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 2408a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 2415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 2425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_LONGPRESS_KEY: 2439552badf3c24d2098d227b0ddca0721b928a10b1Tadashi G. Takaoka keyboardView.onLongPress(tracker); 2445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 24572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka case MSG_UPDATE_BATCH_INPUT: 24672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka tracker.updateBatchInputByTimer(SystemClock.uptimeMillis()); 24772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka startUpdateBatchInputTimer(tracker); 24872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka break; 2495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 252dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void startKeyRepeatTimer(final PointerTracker tracker, final long delay) { 2538a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key key = tracker.getKey(); 25420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (key == null) { 25520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 25620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 2578a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, key.mCode, 0, tracker), delay); 25832c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka } 25932c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka 2602321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 261dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startKeyRepeatTimer(final PointerTracker tracker) { 2625509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka startKeyRepeatTimer(tracker, mKeyRepeatStartTimeout); 2635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelKeyRepeatTimer() { 2665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_REPEAT_KEY); 2675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2690d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka // TODO: Suppress layout changes in key repeat mode 2705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInKeyRepeat() { 2710d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka return hasMessages(MSG_REPEAT_KEY); 2725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2742321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 275212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public void startLongPressTimer(final PointerTracker tracker, final int delay) { 276a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka cancelLongPressTimer(); 277212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka if (delay <= 0) return; 278212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); 2795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2812321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 28298b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer() { 2835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_LONGPRESS_KEY); 2845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 286d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, 28745213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final ObjectAnimator animatorToStart) { 28857372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka if (animatorToCancel == null || animatorToStart == null) { 28957372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka // TODO: Stop using null as a no-operation animator. 29057372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka return; 29157372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka } 29245213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka float startFraction = 0.0f; 29345213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka if (animatorToCancel.isStarted()) { 294b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka animatorToCancel.cancel(); 29545213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka startFraction = 1.0f - animatorToCancel.getAnimatedFraction(); 296b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 29745213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final long startTime = (long)(animatorToStart.getDuration() * startFraction); 29845213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.start(); 29945213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.setCurrentPlayTime(startTime); 300b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 301b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka 302d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeinAnimation(final MainKeyboardView keyboardView) { 303d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator, 304d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeinAnimator); 305d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 306d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 307d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeoutAnimation(final MainKeyboardView keyboardView) { 308d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeinAnimator, 309d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator); 310d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 311d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 3122321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 313dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startTypingStateTimer(final Key typedKey) { 314d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { 315d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 316d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 317d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 31873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final boolean isTyping = isTypingState(); 319f1678ba8024606349bc184cfeaead2be059f7b5bTadashi G. Takaoka removeMessages(MSG_TYPING_STATE_EXPIRED); 320d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 321d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 322d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka // When user hits the space or the enter key, just cancel the while-typing timer. 323d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final int typedCode = typedKey.mCode; 324240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) { 3255141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka if (isTyping) { 3265141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 3275141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 328d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 329d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 330d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 33173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka sendMessageDelayed( 3325509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka obtainMessage(MSG_TYPING_STATE_EXPIRED), mIgnoreAltCodeKeyTimeout); 33373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (isTyping) { 33473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return; 33573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 336d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka startWhileTypingFadeoutAnimation(keyboardView); 33793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 33893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 33993246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 34073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { 34173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return hasMessages(MSG_TYPING_STATE_EXPIRED); 34293246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 34393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3449f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka @Override 3452a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public void startDoubleTapShiftKeyTimer() { 3462a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP_SHIFT_KEY), 3475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka ViewConfiguration.getDoubleTapTimeout()); 3485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3500ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 3512a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public void cancelDoubleTapShiftKeyTimer() { 3522a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka removeMessages(MSG_DOUBLE_TAP_SHIFT_KEY); 353beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka } 354beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 355beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 3562a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public boolean isInDoubleTapShiftKeyTimeout() { 3572a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka return hasMessages(MSG_DOUBLE_TAP_SHIFT_KEY); 3585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 359c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 360c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka @Override 3610ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelKeyTimers() { 3620ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyRepeatTimer(); 3630ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelLongPressTimer(); 364c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 365c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 36672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 36772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(final PointerTracker tracker) { 36872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (mGestureRecognitionUpdateTime <= 0) { 36972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka return; 37072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 37172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 37272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_BATCH_INPUT, tracker), 37372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureRecognitionUpdateTime); 37472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 37572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 37672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 377915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka public void cancelUpdateBatchInputTimer(final PointerTracker tracker) { 378915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 379915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka } 380915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka 381915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka @Override 3822db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers() { 38372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT); 38472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 38572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 3860ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelAllMessages() { 3870ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyTimers(); 3882db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka cancelAllUpdateBatchInputTimers(); 389c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 390c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 391c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 392375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final DrawingHandler mDrawingHandler = new DrawingHandler(this); 393375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 394375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public static class DrawingHandler extends StaticInnerHandlerWrapper<MainKeyboardView> { 395375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private static final int MSG_DISMISS_KEY_PREVIEW = 0; 396375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; 397375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 398375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public DrawingHandler(final MainKeyboardView outerInstance) { 399375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka super(outerInstance); 400375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 401375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 402375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka @Override 403375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void handleMessage(final Message msg) { 404375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final MainKeyboardView mainKeyboardView = getOuterInstance(); 405375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mainKeyboardView == null) return; 406375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 407375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka switch (msg.what) { 408375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka case MSG_DISMISS_KEY_PREVIEW: 409375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final TextView previewText = mainKeyboardView.mKeyPreviewTexts.get( 410375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka tracker.mPointerId); 411375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 412375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText.setVisibility(INVISIBLE); 413375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 414375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka break; 415375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: 416fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mainKeyboardView.showGestureFloatingPreviewText(SuggestedWords.EMPTY); 417375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka break; 418375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 419375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 420375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 421375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissKeyPreview(final long delay, final PointerTracker tracker) { 422375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, tracker), delay); 423375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 424375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 425375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void cancelDismissKeyPreview(final PointerTracker tracker) { 426375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka removeMessages(MSG_DISMISS_KEY_PREVIEW, tracker); 427375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 428375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 429375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void cancelAllDismissKeyPreviews() { 430375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka removeMessages(MSG_DISMISS_KEY_PREVIEW); 431375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 432375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 433375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissGestureFloatingPreviewText(final long delay) { 434375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay); 435375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 436375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 437375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void cancelAllMessages() { 438375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka cancelAllDismissKeyPreviews(); 439375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 440375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 441375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 442dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs) { 443c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka this(context, attrs, R.attr.mainKeyboardViewStyle); 4445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 446dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { 4475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(context, attrs, defStyle); 4485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 44913ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 45013ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean forceNonDistinctMultitouch = prefs.getBoolean( 451a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false); 45213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean hasDistinctMultitouch = context.getPackageManager() 4535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); 45413ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mHasDistinctMultitouch = hasDistinctMultitouch && !forceNonDistinctMultitouch; 455536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka PointerTracker.init(getResources()); 456fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView = new PreviewPlacerView(context, attrs); 45722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 458d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes( 459c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView); 460f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka final int backgroundDimAlpha = mainKeyboardViewAttr.getInt( 461f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka R.styleable.MainKeyboardView_backgroundDimAlpha, 0); 462f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mBackgroundDimAlphaPaint.setColor(Color.BLACK); 463f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha); 464d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mAutoCorrectionSpacebarLedEnabled = mainKeyboardViewAttr.getBoolean( 465c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false); 466d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mAutoCorrectionSpacebarLedIcon = mainKeyboardViewAttr.getDrawable( 467c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedIcon); 468d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextRatio = mainKeyboardViewAttr.getFraction( 469ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextRatio, 1, 1, 1.0f); 470d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextColor = mainKeyboardViewAttr.getColor( 471d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextColor, 0); 472d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextShadowColor = mainKeyboardViewAttr.getColor( 473c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextShadowColor, 0); 474d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt( 475c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha, 4764daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang Constants.Color.ALPHA_OPAQUE); 477d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int languageOnSpacebarFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId( 478c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0); 479d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId( 480c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0); 481d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeinAnimatorResId = mainKeyboardViewAttr.getResourceId( 482c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); 483160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 484d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension( 48508ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f); 486d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension( 48708ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f); 488f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mKeyDetector = new KeyDetector( 489f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier); 490d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mKeyTimerHandler = new KeyTimerHandler(this, mainKeyboardViewAttr); 4910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewOffset = mainKeyboardViewAttr.getDimensionPixelOffset( 4920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewOffset, 0); 4930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize( 4940e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewHeight, 0); 4950e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewLingerTimeout = mainKeyboardViewAttr.getInt( 4960e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); 497375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyPreviewLayoutId = mainKeyboardViewAttr.getResourceId( 498375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewLayout, 0); 4990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (mKeyPreviewLayoutId == 0) { 5000e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mShowKeyPreviewPopup = false; 5010e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 502a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( 503d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); 504d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( 505c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false); 506375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 507375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mGestureFloatingPreviewTextLingerTimeout = mainKeyboardViewAttr.getInt( 508375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); 509d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka PointerTracker.setParameters(mainKeyboardViewAttr); 510fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 511fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText = new GestureFloatingPreviewText( 512fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 513fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mGestureFloatingPreviewText); 514fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 515fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview = new GestureTrailsPreview( 516fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 517fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mGestureTrailsPreview); 518fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 519fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview = new SlidingKeyInputPreview( 520fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 521fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mSlidingKeyInputPreview); 522d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mainKeyboardViewAttr.recycle(); 523160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 524a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardContainer = LayoutInflater.from(getContext()) 525a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka .inflate(moreKeysKeyboardLayoutId, null); 52631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator( 52731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka languageOnSpacebarFadeoutAnimatorResId, this); 52831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator( 52931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeoutAnimatorResId, this); 53031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator( 53131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeinAnimatorResId, this); 532f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka 533f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; 53431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 53531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 536dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private ObjectAnimator loadObjectAnimator(final int resId, final Object target) { 53720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (resId == 0) { 53857372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka // TODO: Stop returning null. 53920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return null; 54020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 54131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator( 54231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka getContext(), resId); 543d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator != null) { 54431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.setTarget(target); 54573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 54631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return animator; 54731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 54873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 54915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 55031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getLanguageOnSpacebarAnimAlpha() { 55131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mLanguageOnSpacebarAnimAlpha; 552d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka } 553d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka 55415f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 555dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setLanguageOnSpacebarAnimAlpha(final int alpha) { 55631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = alpha; 55731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka invalidateKey(mSpaceKey); 55831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 55931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 56015f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 56131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getAltCodeKeyWhileTypingAnimAlpha() { 56231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mAltCodeKeyWhileTypingAnimAlpha; 56331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 56431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 56515f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 566dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) { 5675141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka if (mAltCodeKeyWhileTypingAnimAlpha == alpha) { 5685141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka return; 5695141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 5705141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka // Update the visual of alt-code-key-while-typing. 57131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingAnimAlpha = alpha; 5725141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 5735141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka if (keyboard == null) { 5745141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka return; 5755141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 5765141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka for (final Key key : keyboard.mAltCodeKeysWhileTyping) { 5775141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka invalidateKey(key); 5785141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 5795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 581dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboardActionListener(final KeyboardActionListener listener) { 5825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyboardActionListener = listener; 5835c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.setKeyboardActionListener(listener); 5845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 5875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns the {@link KeyboardActionListener} object. 5885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return the listener attached to this keyboard 5895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 5900efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 5910efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener() { 5925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mKeyboardActionListener; 5935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 595bb4be5444b845655c0eb80bcfbb66f93603802eaTadashi G. Takaoka @Override 5960efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyDetector getKeyDetector() { 5970efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyDetector; 5980efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 5990efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 6000efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 601f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy() { 602f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka return this; 603f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 604f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 605f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka @Override 6060efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public TimerProxy getTimerProxy() { 6070efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyTimerHandler; 6080efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 6090efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 6105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 6115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Attaches a keyboard to this view. The keyboard can be switched at any time and the 6125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * view will re-layout itself to accommodate the keyboard. 6135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see Keyboard 6145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see #getKeyboard() 6155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param keyboard the keyboard to display in this view 6165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 6175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 618dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboard(final Keyboard keyboard) { 6198a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka // Remove any pending messages, except dismissing preview and key repeat. 6208a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka mKeyTimerHandler.cancelLongPressTimer(); 6215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.setKeyboard(keyboard); 6225a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyDetector.setKeyboard( 62308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection()); 6248335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setKeyDetector(mKeyDetector); 625a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.clear(); 6264112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 627240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka mSpaceKey = keyboard.getKey(Constants.CODE_SPACE); 6281f2d0aa6c9b343848ee51e5bc13ccaaadf3ba4feTadashi G. Takaoka mSpaceIcon = (mSpaceKey != null) 6294daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; 6304112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; 6314112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mSpacebarTextSize = keyHeight * mSpacebarTextRatio; 6329c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 633c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_setKeyboard(keyboard); 63448a7681e064ae259b840f0e757da2d716043d893Kurt Partridge } 635f147794fd41491a3383e6aca6d49007f58124068alanv 636f147794fd41491a3383e6aca6d49007f58124068alanv // This always needs to be set since the accessibility state can 637f147794fd41491a3383e6aca6d49007f58124068alanv // potentially change without the keyboard being set again. 638b6ca354431367b625daf9fff5fbe4b1f5ef996abKen Wakasa AccessibleKeyboardViewProxy.getInstance().setKeyboard(); 6395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6410e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka /** 6420e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * Enables or disables the key feedback popup. This is a popup that shows a magnified 6430e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * version of the depressed key. By default the preview is enabled. 6440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @param previewEnabled whether or not to enable the key feedback preview 6450e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @param delay the delay after which the preview is dismissed 6460e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @see #isKeyPreviewPopupEnabled() 6470e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka */ 6480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) { 6490e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mShowKeyPreviewPopup = previewEnabled; 6500e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewLingerTimeout = delay; 6510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 6520e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 653375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 654375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void locatePreviewPlacerView() { 655375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mPreviewPlacerView.getParent() != null) { 656375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 657375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 658375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int width = getWidth(); 659375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int height = getHeight(); 660375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (width == 0 || height == 0) { 661375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In transient state. 662375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 663375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 664375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka getLocationInWindow(mOriginCoords); 665375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final DisplayMetrics dm = getResources().getDisplayMetrics(); 666375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (CoordinateUtils.y(mOriginCoords) < dm.heightPixels / 4) { 667375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In transient state. 668375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 669375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 670375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final View rootView = getRootView(); 671375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (rootView == null) { 672375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka Log.w(TAG, "Cannot find root view"); 673375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 674375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 675375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content); 676375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Note: It'd be very weird if we get null by android.R.id.content. 677375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (windowContentView == null) { 678375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka Log.w(TAG, "Cannot find android.R.id.content view to add PreviewPlacerView"); 679375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 680375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka windowContentView.addView(mPreviewPlacerView); 681375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height); 682375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 683375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 684375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 6850e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka /** 6860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * Returns the enabled state of the key feedback preview 6870e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @return whether or not the key feedback preview is enabled 6880e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @see #setKeyPreviewPopupEnabled(boolean, int) 6890e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka */ 6900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public boolean isKeyPreviewPopupEnabled() { 6910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return mShowKeyPreviewPopup; 6920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 6930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 694375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void addKeyPreview(final TextView keyPreview) { 695375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 696375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.addView( 697375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacerView, 0, 0)); 698375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 699375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 700375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private TextView getKeyPreviewText(final int pointerId) { 701375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka TextView previewText = mKeyPreviewTexts.get(pointerId); 702375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 703375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return previewText; 704375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 705375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final Context context = getContext(); 706375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mKeyPreviewLayoutId != 0) { 707375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText = (TextView)LayoutInflater.from(context).inflate(mKeyPreviewLayoutId, null); 708375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 709375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText = new TextView(context); 710375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 711375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyPreviewTexts.put(pointerId, previewText); 712375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return previewText; 713375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 714375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 715375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void dismissAllKeyPreviews() { 716375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int pointerCount = mKeyPreviewTexts.size(); 717375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka for (int id = 0; id < pointerCount; id++) { 718375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final TextView previewText = mKeyPreviewTexts.get(id); 719375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 720375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText.setVisibility(INVISIBLE); 721375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 722375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 723375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka PointerTracker.setReleasedKeyGraphicsToAllKeys(); 724375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 725375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 7260e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Background state set 7270e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { 7280e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_MIDDLE 7290e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka EMPTY_STATE_SET, 7300e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_has_morekeys } 7310e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }, 7320e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_LEFT 7330e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_left_edge }, 7340e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_left_edge, R.attr.state_has_morekeys } 7350e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }, 7360e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_RIGHT 7370e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_right_edge }, 7380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_right_edge, R.attr.state_has_morekeys } 7390e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7400e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }; 7410e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_MIDDLE = 0; 7420e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_LEFT = 1; 7430e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_RIGHT = 2; 7440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_NORMAL = 0; 7450e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_HAS_MOREKEYS = 1; 7460e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7470e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 7480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void showKeyPreview(final PointerTracker tracker) { 7490e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams; 7500e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 7510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (!mShowKeyPreviewPopup) { 7520e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleOffset = -keyboard.mVerticalGap; 7530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return; 7540e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7550e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7560e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final TextView previewText = getKeyPreviewText(tracker.mPointerId); 7570e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // If the key preview has no parent view yet, add it to the ViewGroup which can place 7580e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // key preview absolutely in SoftInputWindow. 7590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (previewText.getParent() == null) { 7600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka addKeyPreview(previewText); 7610e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7630e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mDrawingHandler.cancelDismissKeyPreview(tracker); 7640e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Key key = tracker.getKey(); 7650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // If key is invalid or IME is already closed, we must not show key preview. 7660e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Trying to show key preview while root window is closed causes 7670e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // WindowManager.BadTokenException. 7680e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (key == null) { 7690e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return; 7700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final KeyDrawParams drawParams = mKeyDrawParams; 7730e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setTextColor(drawParams.mPreviewTextColor); 7740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Drawable background = previewText.getBackground(); 775914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka final String label = key.getPreviewLabel(); 7760e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // What we show as preview should match what we show on a key top in onDraw(). 7770e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (label != null) { 7780e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // TODO Should take care of temporaryShiftLabel here. 7790e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setCompoundDrawables(null, null, null, null); 780914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, 781914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka key.selectPreviewTextSize(drawParams)); 782914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka previewText.setTypeface(key.selectPreviewTypeface(drawParams)); 7830e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setText(label); 7840e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 7850e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setCompoundDrawables(null, null, null, 7860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka key.getPreviewIcon(keyboard.mIconsSet)); 7870e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setText(null); 7880e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7890e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.measure( 7910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 7920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int keyDrawWidth = key.getDrawWidth(); 7930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewWidth = previewText.getMeasuredWidth(); 7940e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewHeight = mKeyPreviewHeight; 7950e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The width and height of visible part of the key preview background. The content marker 7960e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // of the background 9-patch have to cover the visible part of the background. 7970e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleWidth = previewWidth - previewText.getPaddingLeft() 7980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka - previewText.getPaddingRight(); 7990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleHeight = previewHeight - previewText.getPaddingTop() 8000e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka - previewText.getPaddingBottom(); 8010e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The distance between the top edge of the parent key and the bottom of the visible part 8020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // of the key preview background. 8030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleOffset = mKeyPreviewOffset - previewText.getPaddingBottom(); 8040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka getLocationInWindow(mOriginCoords); 8050e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The key preview is horizontally aligned with the center of the visible part of the 8060e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and 8070e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // the left/right background is used if such background is specified. 8080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int statePosition; 8090e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 8100e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka + CoordinateUtils.x(mOriginCoords); 8110e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (previewX < 0) { 8120e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewX = 0; 8130e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_LEFT; 8140e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else if (previewX > getWidth() - previewWidth) { 8150e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewX = getWidth() - previewWidth; 8160e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_RIGHT; 8170e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 8180e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_MIDDLE; 8190e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8200e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The key preview is placed vertically above the top edge of the parent key with an 8210e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // arbitrary offset. 8220e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewY = key.mY - previewHeight + mKeyPreviewOffset 8230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka + CoordinateUtils.y(mOriginCoords); 8240e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8250e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (background != null) { 8260e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int hasMoreKeys = (key.mMoreKeys != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; 8270e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); 8283201e986473f18ed13e1e3dad87c2ecde1d3edc8Tadashi G. Takaoka background.setAlpha(PREVIEW_ALPHA); 8290e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8300e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka ViewLayoutUtils.placeViewAt( 8310e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText, previewX, previewY, previewWidth, previewHeight); 8320e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 8330e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8340e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8350e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8360e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void dismissKeyPreview(final PointerTracker tracker) { 8370e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, tracker); 8380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8390e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 840ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka public void setSlidingKeyInputPreviewEnabled(final boolean enabled) { 841ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mSlidingKeyInputPreview.setPreviewEnabled(enabled); 842ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka } 843ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka 8440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8450e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void showSlidingKeyInputPreview(final PointerTracker tracker) { 8460e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka locatePreviewPlacerView(); 847fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview.setPreviewPosition(tracker); 8480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8490e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8500e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void dismissSlidingKeyInputPreview() { 852fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview.dismissSlidingKeyInputPreview(); 8530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8540e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 855cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa public void setGesturePreviewMode(final boolean drawsGestureTrail, 856375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final boolean drawsGestureFloatingPreviewText) { 857fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText.setPreviewEnabled(drawsGestureFloatingPreviewText); 858cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa mGestureTrailsPreview.setPreviewEnabled(drawsGestureTrail); 859375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 860375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 861375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) { 862375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 863fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText.setSuggetedWords(suggestedWords); 864375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 865375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 866375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissGestureFloatingPreviewText() { 867375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 868375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mDrawingHandler.dismissGestureFloatingPreviewText(mGestureFloatingPreviewTextLingerTimeout); 869375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 870375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 871fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka @Override 872212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public void showGestureTrail(final PointerTracker tracker, 873212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka final boolean showsFloatingPreviewText) { 874375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 875212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka if (showsFloatingPreviewText) { 876212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mGestureFloatingPreviewText.setPreviewPosition(tracker); 877212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 878fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview.setPreviewPosition(tracker); 879375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 880375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 8818335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 882dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 8838335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable); 8848335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 8858335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 886dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 8878335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser); 8880657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka } 8890657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka 8905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 8914331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge protected void onAttachedToWindow() { 8924331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge super.onAttachedToWindow(); 8939c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Notify the ResearchLogger (development only diagnostics) that the keyboard view has 8949c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // been attached. This is needed to properly show the splash screen, which requires that 8959c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // the window token of the KeyboardView be non-null. 8969c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 897c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow(this); 898c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 899c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 900c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka 901c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka @Override 902c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka protected void onDetachedFromWindow() { 903c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka super.onDetachedFromWindow(); 904375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.removeAllViews(); 9059c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Notify the ResearchLogger (development only diagnostics) that the keyboard view has 9069c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // been detached. This is needed to invalidate the reference of {@link MainKeyboardView} 9079c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // to null. 9089c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 909c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onDetachedFromWindow(); 9104331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 9114331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 9124331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge 913a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) { 914a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (key.mMoreKeys == null) { 9155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return null; 91620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 917a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key); 918a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (moreKeysKeyboard == null) { 919a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka moreKeysKeyboard = new MoreKeysKeyboard.Builder( 920a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka context, key, this, mKeyPreviewDrawParams).build(); 921a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.put(key, moreKeysKeyboard); 92220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 9235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 924a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final View container = mMoreKeysKeyboardContainer; 9252affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka final MoreKeysKeyboardView moreKeysKeyboardView = 9262affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); 9272affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); 928b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 9292affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka return moreKeysKeyboardView; 9305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 9325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 933d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * Called when a key is long pressed. 9345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param tracker the pointer tracker which pressed the parent key 9355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 93696efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka private void onLongPress(final PointerTracker tracker) { 937a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 93896efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 939a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 940a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final Key key = tracker.getKey(); 941a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (key == null) { 94296efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 943a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 9449c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 945c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_onLongPress(); 9469bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 947f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final KeyboardActionListener listener = mKeyboardActionListener; 9489552badf3c24d2098d227b0ddca0721b928a10b1Tadashi G. Takaoka if (key.hasNoPanelAutoMoreKey()) { 949f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final int moreKeyCode = key.mMoreKeys[0].mCode; 9503708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka tracker.onLongPressed(); 9516455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka listener.onPressKey(moreKeyCode, false /* isRepeatKey */, true /* isSinglePointer */); 952f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onCodeInput(moreKeyCode, 953f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 954f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onReleaseKey(moreKeyCode, false /* withSliding */); 95596efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 9563708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka } 957f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final int code = key.mCode; 958a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) { 9593708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka // Long pressing the space key invokes IME switcher dialog. 960f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka if (listener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) { 9616dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 962f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onReleaseKey(code, false /* withSliding */); 96396efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 9646dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 9656dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 96696efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka openMoreKeysPanel(key, tracker); 9676dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 9686dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 96996efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka private void openMoreKeysPanel(final Key key, final PointerTracker tracker) { 970a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = onCreateMoreKeysPanel(key, getContext()); 9719d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (moreKeysPanel == null) { 97296efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 9735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 97463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 975547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 976547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.getLastCoordinates(lastCoords); 977a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !key.noKeyPreview(); 9787ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually horizontally aligned with the center of the parent key. 9797ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more 9807ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // keys keyboard is placed at the touch point of the parent key. 9817ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled) 982547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka ? CoordinateUtils.x(lastCoords) 983a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka : key.mX + key.mWidth / 2; 9847ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually vertically aligned with the top edge of the parent key 9857ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically 9867ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // aligned with the bottom edge of the visible part of the key preview. 98729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@code mPreviewVisibleOffset} has been set appropriately in 98829d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@link KeyboardView#showKeyPreview(PointerTracker)}. 989a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int pointY = key.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset; 990fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); 991547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(CoordinateUtils.x(lastCoords)); 992547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(CoordinateUtils.y(lastCoords)); 993e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaoka tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); 9945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 9965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 997a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 99863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return true; 9995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 100020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return PointerTracker.isAnyInSlidingKeyInput(); 10015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1003d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 1004d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public void onShowMoreKeysPanel(final MoreKeysPanel panel) { 10051b6eea89037158a1e271730eacdacb8b6e550d3aTadashi G. Takaoka locatePreviewPlacerView(); 10060e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka // TODO: Remove this check 10070e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka if (panel.isShowingInParent()) { 10080e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka panel.dismissMoreKeysPanel(); 1009d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1010a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mPreviewPlacerView.addView(panel.getContainerView()); 1011d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMoreKeysPanel = panel; 1012a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka dimEntireKeyboard(true /* dimmed */); 1013d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1014d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 1015d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public boolean isShowingMoreKeysPanel() { 1016a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return mMoreKeysPanel != null && mMoreKeysPanel.isShowingInParent(); 1017d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1018d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 1019d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 10200e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { 1021d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka PointerTracker.dismissAllMoreKeysPanels(); 1022d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1023d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 1024d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 10250e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { 1026d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka dimEntireKeyboard(false /* dimmed */); 1027d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 1028d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mPreviewPlacerView.removeView(mMoreKeysPanel.getContainerView()); 1029d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMoreKeysPanel = null; 1030d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1031d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1032d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 10335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 1034dc2ee7772402633817702e95c2a5b17f6dec03ebalanv public boolean dispatchTouchEvent(MotionEvent event) { 1035dc2ee7772402633817702e95c2a5b17f6dec03ebalanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 1036dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return AccessibleKeyboardViewProxy.getInstance().dispatchTouchEvent(event); 1037dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 1038dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return super.dispatchTouchEvent(event); 1039dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 1040dc2ee7772402633817702e95c2a5b17f6dec03ebalanv 1041dc2ee7772402633817702e95c2a5b17f6dec03ebalanv @Override 1042dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean onTouchEvent(final MotionEvent me) { 104346286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka if (getKeyboard() == null) { 104446286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka return false; 104546286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka } 1046310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka // TODO: Add multi-touch to single-touch event converter for non-distinct multi-touch 1047310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka // device. 1048310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka return processMotionEvent(me); 1049c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 1050c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 1051dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean processMotionEvent(final MotionEvent me) { 1052f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final boolean nonDistinctMultitouch = !mHasDistinctMultitouch; 10535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int action = me.getActionMasked(); 10545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int pointerCount = me.getPointerCount(); 10555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int oldPointerCount = mOldPointerCount; 10565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mOldPointerCount = pointerCount; 10575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 10595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // If the device does not have distinct multi-touch support panel, ignore all multi-touch 10605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // events except a transition from/to single-touch. 1061f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) { 10625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 10635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final long eventTime = me.getEventTime(); 10665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int index = me.getActionIndex(); 10675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int id = me.getPointerId(index); 106835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int x = (int)me.getX(index); 106935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int y = (int)me.getY(index); 107035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 1071fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // TODO: This might be moved to the tracker.processMotionEvent() call below. 1072fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka if (ENABLE_USABILITY_STUDY_LOG && action != MotionEvent.ACTION_MOVE) { 1073fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka writeUsabilityStudyLog(me, action, eventTime, index, id, x, y); 1074d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 1075fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // TODO: This should be moved to the tracker.processMotionEvent() call below. 1076fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // Currently the same "move" event is being logged twice. 10779c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 1078fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka ResearchLogger.mainKeyboardView_processMotionEvent( 1079fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka me, action, eventTime, index, id, x, y); 108015d4793911fa305e0a58aced925961e948582979satok } 10815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1082f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (mKeyTimerHandler.isInKeyRepeat()) { 1083e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 10845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Key repeating timer will be canceled if 2 or more keys are in action, and current 10855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // event (UP or DOWN) is non-modifier key. 10865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount > 1 && !tracker.isModifier()) { 1087f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelKeyRepeatTimer(); 10885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Up event will pass through. 10905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 10935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Translate mutli-touch event to single-touch events on the device that has no distinct 10945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // multi-touch panel. 1095f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch) { 10965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Use only main (id=0) pointer tracker. 1097e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 10985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount == 1 && oldPointerCount == 2) { 10995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Multi-touch to single touch transition. 11005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send a down event for the latest pointer if the key is different from the 11015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // previous key. 1102e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key newKey = tracker.getKeyOn(x, y); 1103e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (mOldKey != newKey) { 11040efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka tracker.onDownEvent(x, y, eventTime, this); 1105fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka if (action == MotionEvent.ACTION_UP) { 1106906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka tracker.onUpEvent(x, y, eventTime); 1107fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 11085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 2 && oldPointerCount == 1) { 11105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Single-touch to multi-touch transition. 11115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send an up event for the last pointer. 1112547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 1113547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka mOldKey = tracker.getKeyOn( 1114547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords)); 1115547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.onUpEvent( 1116547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime); 11175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 1 && oldPointerCount == 1) { 11188ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 11195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 11205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount 11215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka + " (old " + oldPointerCount + ")"); 11225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 11245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (action == MotionEvent.ACTION_MOVE) { 11275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka for (int i = 0; i < pointerCount; i++) { 1128d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final int pointerId = me.getPointerId(i); 1129e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker( 1130d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge pointerId, this); 113135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int px = (int)me.getX(i); 113235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int py = (int)me.getY(i); 113335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang tracker.onMoveEvent(px, py, eventTime, me); 1134d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge if (ENABLE_USABILITY_STUDY_LOG) { 1135fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka writeUsabilityStudyLog(me, action, eventTime, i, pointerId, px, py); 1136d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 11371bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // TODO: This seems to be no longer necessary, and confusing because it leads to 11381bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // duplicate MotionEvents being recorded. 11391bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 11401bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // ResearchLogger.mainKeyboardView_processMotionEvent( 11411bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // me, action, eventTime, i, pointerId, px, py); 11421bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // } 11435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 1145e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 1146e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 11475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 11505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1152fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka private static void writeUsabilityStudyLog(final MotionEvent me, final int action, 1153fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final long eventTime, final int index, final int id, final int x, final int y) { 1154fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final String eventTag; 1155fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka switch (action) { 1156fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_UP: 1157fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Up]"; 1158fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1159fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 1160fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Down]"; 1161fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1162fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 1163fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[PointerUp]"; 1164fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1165fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 1166fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[PointerDown]"; 1167fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1168fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 1169fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Move]"; 1170fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1171fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka default: 1172fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Action" + action + "]"; 1173fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1174fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 1175fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final float size = me.getSize(index); 1176fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final float pressure = me.getPressure(index); 1177fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka UsabilityStudyLogUtils.getInstance().write( 1178fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag + eventTime + "," + id + "," + x + "," + y + "," + size + "," + pressure); 1179fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 1180fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka 11815c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka public void cancelAllOngoingEvents() { 1182375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyTimerHandler.cancelAllMessages(); 1183375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mDrawingHandler.cancelAllMessages(); 11845c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissAllKeyPreviews(); 11855c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissGestureFloatingPreviewText(); 11865c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissSlidingKeyInputPreview(); 11875c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka PointerTracker.dismissAllMoreKeysPanels(); 11885c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka PointerTracker.cancelAllPointerTrackers(); 1189375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 1190375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 11915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void closing() { 11925c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka cancelAllOngoingEvents(); 1193a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.clear(); 11945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1196586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette /** 1197c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka * Receives hover events from the input framework. 1198586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * 1199586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @param event The motion event to be dispatched. 1200586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @return {@code true} if the event was handled by the view, {@code false} 1201586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * otherwise 1202586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette */ 1203c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka @Override 1204dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean dispatchHoverEvent(final MotionEvent event) { 12055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 1206e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 1207586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker); 12085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 12095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1210586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette // Reflection doesn't support calling superclass methods. 12115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 12125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 121322b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 1214dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateShortcutKey(final boolean available) { 12157bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 121620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (keyboard == null) { 121720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 121820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1219240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT); 122020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (shortcutKey == null) { 122120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 122220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 12237bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka shortcutKey.setEnabled(available); 12247bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka invalidateKey(shortcutKey); 12255afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka } 12265afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka 1227dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, 1228dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final boolean needsToDisplayLanguage, final boolean hasMultipleEnabledIMEsOrSubtypes) { 12294112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mNeedsToDisplayLanguage = needsToDisplayLanguage; 1230fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; 1231fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; 1232d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator == null) { 1233aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka mNeedsToDisplayLanguage = false; 12344c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } else { 1235dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka if (subtypeChanged && needsToDisplayLanguage) { 12364daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); 123731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (animator.isStarted()) { 123831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.cancel(); 123931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 1240d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka animator.start(); 1241dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } else { 124231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (!animator.isStarted()) { 124331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha; 124431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 1245dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } 12464c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } 12474112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 12484112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 12494112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1250dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateAutoCorrectionState(final boolean isAutoCorrection) { 125120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (!mAutoCorrectionSpacebarLedEnabled) { 125220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 125320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 12544112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedOn = isAutoCorrection; 12554112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 125622b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 125722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 1258a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private void dimEntireKeyboard(final boolean dimmed) { 1259f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka final boolean needsRedrawing = mNeedsToDimEntireKeyboard != dimmed; 1260f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mNeedsToDimEntireKeyboard = dimmed; 1261f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka if (needsRedrawing) { 1262f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka invalidateAllKeys(); 1263f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1264f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1265f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 1266f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka @Override 1267f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka protected void onDraw(final Canvas canvas) { 1268f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka super.onDraw(canvas); 1269f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 1270f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka // Overlay a dark rectangle to dim. 1271f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka if (mNeedsToDimEntireKeyboard) { 127208ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mBackgroundDimAlphaPaint); 1273f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1274f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1275f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 127622b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka @Override 1277dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, 1278dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final KeyDrawParams params) { 12796bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.altCodeWhileTyping() && key.isEnabled()) { 128073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha; 128173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 1282240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (key.mCode == Constants.CODE_SPACE) { 1283bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawSpacebar(key, canvas, paint); 12844112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Whether space key needs to show the "..." popup hint for special purposes 1285fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) { 1286bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 12874112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 1288240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (key.mCode == Constants.CODE_LANGUAGE_SWITCH) { 128981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 1290fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 1291b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka } else { 1292b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 129322b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 129422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 12954112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 129608ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka private static boolean fitsTextIntoWidth(final int width, final String text, 129708ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final Paint paint) { 1298bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(1.0f); 129908ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final float textWidth = TypefaceUtils.getLabelWidth(text, paint); 130020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (textWidth < width) { 130120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return true; 130220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1303bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1304bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final float scaleX = width / textWidth; 130520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) { 130620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return false; 130720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1308bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1309bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(scaleX); 131008ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka return TypefaceUtils.getLabelWidth(text, paint) < width; 1311bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 1312bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1313bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Layout language name on spacebar. 131408ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka private static String layoutLanguageOnSpacebar(final Paint paint, 131508ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final InputMethodSubtype subtype, final int width) { 1316bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Choose appropriate language name to fit into the width. 1317a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String fullText = SubtypeLocaleUtils.getFullDisplayName(subtype); 131820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, fullText, paint)) { 131920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return fullText; 1320bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 1321bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1322a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String middleText = SubtypeLocaleUtils.getMiddleDisplayName(subtype); 132320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, middleText, paint)) { 132420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return middleText; 13254112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13264112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1327a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String shortText = SubtypeLocaleUtils.getShortDisplayName(subtype); 132820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, shortText, paint)) { 132920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return shortText; 13304112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13314112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1332bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return ""; 13334112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13344112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1335dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void drawSpacebar(final Key key, final Canvas canvas, final Paint paint) { 1336bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka final int width = key.mWidth; 1337b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final int height = key.mHeight; 13384112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1339f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka // If input language are explicitly selected. 1340bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mNeedsToDisplayLanguage) { 1341bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextAlign(Align.CENTER); 1342bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTypeface(Typeface.DEFAULT); 1343bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextSize(mSpacebarTextSize); 1344bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final InputMethodSubtype subtype = getKeyboard().mId.mSubtype; 1345bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final String language = layoutLanguageOnSpacebar(paint, subtype, width); 13464112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw language text with shadow 13474112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float descent = paint.descent(); 13484112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float textHeight = -paint.ascent() + descent; 1349b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final float baseline = height / 2 + textHeight / 2; 1350aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextShadowColor); 135131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 13524112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent - 1, paint); 1353aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextColor); 135431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 13554112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent, paint); 13564112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13574112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 13584112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw the spacebar icon at the bottom 1359bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mAutoCorrectionSpacebarLedOn) { 13604112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; 13614112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); 13624112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 13634112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1364bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight); 13654112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } else if (mSpaceIcon != null) { 13664112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = mSpaceIcon.getIntrinsicWidth(); 13674112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mSpaceIcon.getIntrinsicHeight(); 13684112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 13694112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1370bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight); 13714112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13724112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 1373c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa 1374c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa public void deallocateMemory() { 1375c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa mGestureTrailsPreview.deallocateMemory(); 1376c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa } 13775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka} 1378