MainKeyboardView.java revision 5433ce64c0f141bc4ee82912844f47f575654af5
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 120bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /** Listener for {@link KeyboardActionListener}. */ 121bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private KeyboardActionListener mKeyboardActionListener; 122bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka 123bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /* Space key and its icons */ 1244112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Key mSpaceKey; 1254112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Drawable mSpaceIcon; 126bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw language name on spacebar. 12731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private final int mLanguageOnSpacebarFinalAlpha; 12831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; 129bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mNeedsToDisplayLanguage; 130fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka private boolean mHasMultipleEnabledIMEsOrSubtypes; 1314daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; 1324112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final float mSpacebarTextRatio; 1334112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private float mSpacebarTextSize; 1344112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextColor; 1354112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextShadowColor; 136bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // The minimum x-scale to fit the language name on spacebar. 137bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f; 138bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw auto correction LED on spacebar. 139bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mAutoCorrectionSpacebarLedOn; 140bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final boolean mAutoCorrectionSpacebarLedEnabled; 141bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final Drawable mAutoCorrectionSpacebarLedIcon; 142bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private static final int SPACE_LED_LENGTH_PERCENT = 80; 14315d4793911fa305e0a58aced925961e948582979satok 14473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka // Stuff to draw altCodeWhileTyping keys. 14531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; 14631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; 1474daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; 14873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 149375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Preview placer view 150375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final PreviewPlacerView mPreviewPlacerView; 151375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final int[] mOriginCoords = CoordinateUtils.newInstance(); 152fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final GestureFloatingPreviewText mGestureFloatingPreviewText; 153fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final GestureTrailsPreview mGestureTrailsPreview; 154fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final SlidingKeyInputPreview mSlidingKeyInputPreview; 155375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 1560e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Key preview 1570e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int PREVIEW_ALPHA = 240; 158375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final int mKeyPreviewLayoutId; 1590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final int mKeyPreviewOffset; 1600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final int mKeyPreviewHeight; 161375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final SparseArray<TextView> mKeyPreviewTexts = CollectionUtils.newSparseArray(); 1620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); 1630e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private boolean mShowKeyPreviewPopup = true; 1640e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private int mKeyPreviewLingerTimeout; 1650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 1662affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka // More keys keyboard 167f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka private final Paint mBackgroundDimAlphaPaint = new Paint(); 168f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka private boolean mNeedsToDimEntireKeyboard; 169a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private final View mMoreKeysKeyboardContainer; 170a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = 171a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka CollectionUtils.newWeakHashMap(); 1722affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint; 173d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka // More keys panel (used by both more keys keyboard and more suggestions view) 174d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka // TODO: Consider extending to support multiple more keys panels 175d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka private MoreKeysPanel mMoreKeysPanel; 1765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 177375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Gesture floating preview text 178375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // TODO: Make this parameter customizable by user via settings. 179375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private int mGestureFloatingPreviewTextLingerTimeout; 180375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 181d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka private KeyDetector mKeyDetector; 18213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka private final boolean mHasDistinctMultitouch; 1835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private int mOldPointerCount = 1; 184e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mOldKey; 1855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 186160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka private final KeyTimerHandler mKeyTimerHandler; 1875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 188a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka private static final class KeyTimerHandler extends StaticInnerHandlerWrapper<MainKeyboardView> 1892321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka implements TimerProxy { 19027e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_TYPING_STATE_EXPIRED = 0; 191f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_REPEAT_KEY = 1; 192f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_LONGPRESS_KEY = 2; 1932a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka private static final int MSG_DOUBLE_TAP_SHIFT_KEY = 3; 19472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private static final int MSG_UPDATE_BATCH_INPUT = 4; 1955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1965509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mIgnoreAltCodeKeyTimeout; 19772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private final int mGestureRecognitionUpdateTime; 1985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1995509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public KeyTimerHandler(final MainKeyboardView outerInstance, 2005509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka final TypedArray mainKeyboardViewAttr) { 2015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(outerInstance); 2025509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 2035509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( 2045509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); 20572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt( 20672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0); 2075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 210dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void handleMessage(final Message msg) { 211c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 21248d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka if (keyboardView == null) { 21348d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka return; 21448d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka } 2155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 2165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka switch (msg.what) { 21727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka case MSG_TYPING_STATE_EXPIRED: 21827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 21927e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka break; 2205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_REPEAT_KEY: 2218126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka tracker.onKeyRepeat(msg.arg1); 2225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 2235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_LONGPRESS_KEY: 2249552badf3c24d2098d227b0ddca0721b928a10b1Tadashi G. Takaoka keyboardView.onLongPress(tracker); 2255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 22672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka case MSG_UPDATE_BATCH_INPUT: 22772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka tracker.updateBatchInputByTimer(SystemClock.uptimeMillis()); 22872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka startUpdateBatchInputTimer(tracker); 22972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka break; 2305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2338126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka @Override 2348126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka public void startKeyRepeatTimer(final PointerTracker tracker, final int delay) { 2358a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key key = tracker.getKey(); 2368126e79e085c75f0eadaaf71e0a4ed1a2b83d892Tadashi G. Takaoka if (key == null || delay == 0) { 23720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 23820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 2398a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, key.mCode, 0, tracker), delay); 24032c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka } 24132c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka 2425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelKeyRepeatTimer() { 2435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_REPEAT_KEY); 2445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2460d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka // TODO: Suppress layout changes in key repeat mode 2475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInKeyRepeat() { 2480d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka return hasMessages(MSG_REPEAT_KEY); 2495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2512321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 252212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public void startLongPressTimer(final PointerTracker tracker, final int delay) { 253a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka cancelLongPressTimer(); 254212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka if (delay <= 0) return; 255212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); 2565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2582321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 25998b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer() { 2605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_LONGPRESS_KEY); 2615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 263d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, 26445213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final ObjectAnimator animatorToStart) { 26557372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka if (animatorToCancel == null || animatorToStart == null) { 26657372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka // TODO: Stop using null as a no-operation animator. 26757372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka return; 26857372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka } 26945213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka float startFraction = 0.0f; 27045213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka if (animatorToCancel.isStarted()) { 271b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka animatorToCancel.cancel(); 27245213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka startFraction = 1.0f - animatorToCancel.getAnimatedFraction(); 273b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 27445213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final long startTime = (long)(animatorToStart.getDuration() * startFraction); 27545213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.start(); 27645213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.setCurrentPlayTime(startTime); 277b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 278b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka 279d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeinAnimation(final MainKeyboardView keyboardView) { 280d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator, 281d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeinAnimator); 282d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 283d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 284d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeoutAnimation(final MainKeyboardView keyboardView) { 285d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeinAnimator, 286d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator); 287d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 288d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 2892321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 290dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startTypingStateTimer(final Key typedKey) { 291d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { 292d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 293d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 294d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 29573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final boolean isTyping = isTypingState(); 296f1678ba8024606349bc184cfeaead2be059f7b5bTadashi G. Takaoka removeMessages(MSG_TYPING_STATE_EXPIRED); 297d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 298d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 299d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka // When user hits the space or the enter key, just cancel the while-typing timer. 300d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final int typedCode = typedKey.mCode; 301240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) { 3025141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka if (isTyping) { 3035141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 3045141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 305d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 306d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 307d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 30873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka sendMessageDelayed( 3095509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka obtainMessage(MSG_TYPING_STATE_EXPIRED), mIgnoreAltCodeKeyTimeout); 31073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (isTyping) { 31173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return; 31273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 313d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka startWhileTypingFadeoutAnimation(keyboardView); 31493246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 31593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 31693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 31773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { 31873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return hasMessages(MSG_TYPING_STATE_EXPIRED); 31993246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 32093246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3219f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka @Override 3222a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public void startDoubleTapShiftKeyTimer() { 3232a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP_SHIFT_KEY), 3245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka ViewConfiguration.getDoubleTapTimeout()); 3255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3270ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 3282a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public void cancelDoubleTapShiftKeyTimer() { 3292a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka removeMessages(MSG_DOUBLE_TAP_SHIFT_KEY); 330beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka } 331beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 332beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 3332a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka public boolean isInDoubleTapShiftKeyTimeout() { 3342a9882a433e2372ac32fbc0def578d4d9a97a676Tadashi G. Takaoka return hasMessages(MSG_DOUBLE_TAP_SHIFT_KEY); 3355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 336c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 337c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka @Override 3380ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelKeyTimers() { 3390ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyRepeatTimer(); 3400ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelLongPressTimer(); 341c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 342c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 34372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 34472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(final PointerTracker tracker) { 34572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (mGestureRecognitionUpdateTime <= 0) { 34672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka return; 34772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 34872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 34972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_BATCH_INPUT, tracker), 35072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureRecognitionUpdateTime); 35172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 35272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 35372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 354915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka public void cancelUpdateBatchInputTimer(final PointerTracker tracker) { 355915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 356915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka } 357915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka 358915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka @Override 3592db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers() { 36072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT); 36172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 36272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 3630ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelAllMessages() { 3640ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyTimers(); 3652db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka cancelAllUpdateBatchInputTimers(); 366c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 367c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 368c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 369375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final DrawingHandler mDrawingHandler = new DrawingHandler(this); 370375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 371375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public static class DrawingHandler extends StaticInnerHandlerWrapper<MainKeyboardView> { 372375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private static final int MSG_DISMISS_KEY_PREVIEW = 0; 373375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; 374375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 375375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public DrawingHandler(final MainKeyboardView outerInstance) { 376375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka super(outerInstance); 377375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 378375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 379375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka @Override 380375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void handleMessage(final Message msg) { 381375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final MainKeyboardView mainKeyboardView = getOuterInstance(); 382375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mainKeyboardView == null) return; 383375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 384375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka switch (msg.what) { 385375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka case MSG_DISMISS_KEY_PREVIEW: 386375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final TextView previewText = mainKeyboardView.mKeyPreviewTexts.get( 387375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka tracker.mPointerId); 388375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 389375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText.setVisibility(INVISIBLE); 390375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 391375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka break; 392375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: 393fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mainKeyboardView.showGestureFloatingPreviewText(SuggestedWords.EMPTY); 394375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka break; 395375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 396375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 397375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 398375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissKeyPreview(final long delay, final PointerTracker tracker) { 399375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, tracker), delay); 400375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 401375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 402375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void cancelDismissKeyPreview(final PointerTracker tracker) { 403375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka removeMessages(MSG_DISMISS_KEY_PREVIEW, tracker); 404375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 405375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 406375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void cancelAllDismissKeyPreviews() { 407375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka removeMessages(MSG_DISMISS_KEY_PREVIEW); 408375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 409375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 410375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissGestureFloatingPreviewText(final long delay) { 411375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay); 412375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 413375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 414375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void cancelAllMessages() { 415375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka cancelAllDismissKeyPreviews(); 416375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 417375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 418375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 419dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs) { 420c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka this(context, attrs, R.attr.mainKeyboardViewStyle); 4215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 423dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { 4245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(context, attrs, defStyle); 4255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 42613ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 42713ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean forceNonDistinctMultitouch = prefs.getBoolean( 428a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false); 42913ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean hasDistinctMultitouch = context.getPackageManager() 4305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); 43113ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mHasDistinctMultitouch = hasDistinctMultitouch && !forceNonDistinctMultitouch; 432536438a45e5dc9d75c6c1a7d75262c41ce8f953cTadashi G. Takaoka PointerTracker.init(getResources()); 433fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView = new PreviewPlacerView(context, attrs); 43422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 435d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes( 436c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView); 437f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka final int backgroundDimAlpha = mainKeyboardViewAttr.getInt( 438f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka R.styleable.MainKeyboardView_backgroundDimAlpha, 0); 439f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mBackgroundDimAlphaPaint.setColor(Color.BLACK); 440f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha); 441d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mAutoCorrectionSpacebarLedEnabled = mainKeyboardViewAttr.getBoolean( 442c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false); 443d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mAutoCorrectionSpacebarLedIcon = mainKeyboardViewAttr.getDrawable( 444c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedIcon); 445d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextRatio = mainKeyboardViewAttr.getFraction( 446ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextRatio, 1, 1, 1.0f); 447d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextColor = mainKeyboardViewAttr.getColor( 448d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextColor, 0); 449d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextShadowColor = mainKeyboardViewAttr.getColor( 450c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextShadowColor, 0); 451d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt( 452c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha, 4534daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang Constants.Color.ALPHA_OPAQUE); 454d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int languageOnSpacebarFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId( 455c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0); 456d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId( 457c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0); 458d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeinAnimatorResId = mainKeyboardViewAttr.getResourceId( 459c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); 460160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 461d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension( 46208ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f); 463d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension( 46408ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f); 465f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mKeyDetector = new KeyDetector( 466f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier); 467d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mKeyTimerHandler = new KeyTimerHandler(this, mainKeyboardViewAttr); 4680e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewOffset = mainKeyboardViewAttr.getDimensionPixelOffset( 4690e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewOffset, 0); 4700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize( 4710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewHeight, 0); 4720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewLingerTimeout = mainKeyboardViewAttr.getInt( 4730e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); 474375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyPreviewLayoutId = mainKeyboardViewAttr.getResourceId( 475375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewLayout, 0); 4760e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (mKeyPreviewLayoutId == 0) { 4770e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mShowKeyPreviewPopup = false; 4780e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 479a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( 480d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); 481d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( 482c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false); 483375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 484375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mGestureFloatingPreviewTextLingerTimeout = mainKeyboardViewAttr.getInt( 485375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); 486d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka PointerTracker.setParameters(mainKeyboardViewAttr); 487fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 488fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText = new GestureFloatingPreviewText( 489fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 490fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mGestureFloatingPreviewText); 491fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 492fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview = new GestureTrailsPreview( 493fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 494fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mGestureTrailsPreview); 495fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 496fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview = new SlidingKeyInputPreview( 497fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 498fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mSlidingKeyInputPreview); 499d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mainKeyboardViewAttr.recycle(); 500160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 501a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardContainer = LayoutInflater.from(getContext()) 502a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka .inflate(moreKeysKeyboardLayoutId, null); 50331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator( 50431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka languageOnSpacebarFadeoutAnimatorResId, this); 50531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator( 50631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeoutAnimatorResId, this); 50731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator( 50831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeinAnimatorResId, this); 509f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka 510f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; 51131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 51231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 513dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private ObjectAnimator loadObjectAnimator(final int resId, final Object target) { 51420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (resId == 0) { 51557372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka // TODO: Stop returning null. 51620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return null; 51720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 51831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator( 51931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka getContext(), resId); 520d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator != null) { 52131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.setTarget(target); 52273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 52331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return animator; 52431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 52573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 52615f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 52731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getLanguageOnSpacebarAnimAlpha() { 52831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mLanguageOnSpacebarAnimAlpha; 529d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka } 530d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka 53115f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 532dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setLanguageOnSpacebarAnimAlpha(final int alpha) { 53331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = alpha; 53431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka invalidateKey(mSpaceKey); 53531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 53631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 53715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 53831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getAltCodeKeyWhileTypingAnimAlpha() { 53931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mAltCodeKeyWhileTypingAnimAlpha; 54031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 54131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 54215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 543dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) { 5445141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka if (mAltCodeKeyWhileTypingAnimAlpha == alpha) { 5455141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka return; 5465141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 5475141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka // Update the visual of alt-code-key-while-typing. 54831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingAnimAlpha = alpha; 5495141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 5505141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka if (keyboard == null) { 5515141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka return; 5525141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 5535141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka for (final Key key : keyboard.mAltCodeKeysWhileTyping) { 5545141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka invalidateKey(key); 5555141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 5565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 558dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboardActionListener(final KeyboardActionListener listener) { 5595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyboardActionListener = listener; 5605c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.setKeyboardActionListener(listener); 5615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 5645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns the {@link KeyboardActionListener} object. 5655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return the listener attached to this keyboard 5665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 5670efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 5680efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener() { 5695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mKeyboardActionListener; 5705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 572bb4be5444b845655c0eb80bcfbb66f93603802eaTadashi G. Takaoka @Override 5730efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyDetector getKeyDetector() { 5740efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyDetector; 5750efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 5760efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 5770efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 578f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy() { 579f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka return this; 580f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 581f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 582f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka @Override 5830efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public TimerProxy getTimerProxy() { 5840efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyTimerHandler; 5850efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 5860efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 5875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 5885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Attaches a keyboard to this view. The keyboard can be switched at any time and the 5895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * view will re-layout itself to accommodate the keyboard. 5905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see Keyboard 5915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see #getKeyboard() 5925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param keyboard the keyboard to display in this view 5935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 5945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 595dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboard(final Keyboard keyboard) { 5968a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka // Remove any pending messages, except dismissing preview and key repeat. 5978a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka mKeyTimerHandler.cancelLongPressTimer(); 5985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.setKeyboard(keyboard); 5995a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyDetector.setKeyboard( 60008ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection()); 6018335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setKeyDetector(mKeyDetector); 602a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.clear(); 6034112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 604240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka mSpaceKey = keyboard.getKey(Constants.CODE_SPACE); 6051f2d0aa6c9b343848ee51e5bc13ccaaadf3ba4feTadashi G. Takaoka mSpaceIcon = (mSpaceKey != null) 6064daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; 6074112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; 6084112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mSpacebarTextSize = keyHeight * mSpacebarTextRatio; 6099c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 610c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_setKeyboard(keyboard); 61148a7681e064ae259b840f0e757da2d716043d893Kurt Partridge } 612f147794fd41491a3383e6aca6d49007f58124068alanv 613f147794fd41491a3383e6aca6d49007f58124068alanv // This always needs to be set since the accessibility state can 614f147794fd41491a3383e6aca6d49007f58124068alanv // potentially change without the keyboard being set again. 615b6ca354431367b625daf9fff5fbe4b1f5ef996abKen Wakasa AccessibleKeyboardViewProxy.getInstance().setKeyboard(); 6165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6180e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka /** 6190e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * Enables or disables the key feedback popup. This is a popup that shows a magnified 6200e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * version of the depressed key. By default the preview is enabled. 6210e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @param previewEnabled whether or not to enable the key feedback preview 6220e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @param delay the delay after which the preview is dismissed 6230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @see #isKeyPreviewPopupEnabled() 6240e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka */ 6250e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) { 6260e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mShowKeyPreviewPopup = previewEnabled; 6270e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewLingerTimeout = delay; 6280e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 6290e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 630375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 631375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void locatePreviewPlacerView() { 632375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mPreviewPlacerView.getParent() != null) { 633375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 634375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 635375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int width = getWidth(); 636375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int height = getHeight(); 637375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (width == 0 || height == 0) { 638375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In transient state. 639375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 640375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 641375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka getLocationInWindow(mOriginCoords); 642375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final DisplayMetrics dm = getResources().getDisplayMetrics(); 643375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (CoordinateUtils.y(mOriginCoords) < dm.heightPixels / 4) { 644375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In transient state. 645375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 646375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 647375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final View rootView = getRootView(); 648375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (rootView == null) { 649375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka Log.w(TAG, "Cannot find root view"); 650375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 651375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 652375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content); 653375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Note: It'd be very weird if we get null by android.R.id.content. 654375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (windowContentView == null) { 655375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka Log.w(TAG, "Cannot find android.R.id.content view to add PreviewPlacerView"); 656375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 657375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka windowContentView.addView(mPreviewPlacerView); 658375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height); 659375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 660375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 661375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 6620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka /** 6630e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * Returns the enabled state of the key feedback preview 6640e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @return whether or not the key feedback preview is enabled 6650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @see #setKeyPreviewPopupEnabled(boolean, int) 6660e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka */ 6670e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public boolean isKeyPreviewPopupEnabled() { 6680e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return mShowKeyPreviewPopup; 6690e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 6700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 671375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void addKeyPreview(final TextView keyPreview) { 672375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 673375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.addView( 674375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacerView, 0, 0)); 675375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 676375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 677375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private TextView getKeyPreviewText(final int pointerId) { 678375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka TextView previewText = mKeyPreviewTexts.get(pointerId); 679375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 680375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return previewText; 681375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 682375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final Context context = getContext(); 683375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mKeyPreviewLayoutId != 0) { 684375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText = (TextView)LayoutInflater.from(context).inflate(mKeyPreviewLayoutId, null); 685375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 686375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText = new TextView(context); 687375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 688375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyPreviewTexts.put(pointerId, previewText); 689375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return previewText; 690375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 691375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 692375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void dismissAllKeyPreviews() { 693375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int pointerCount = mKeyPreviewTexts.size(); 694375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka for (int id = 0; id < pointerCount; id++) { 695375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final TextView previewText = mKeyPreviewTexts.get(id); 696375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 697375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText.setVisibility(INVISIBLE); 698375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 699375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 700375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka PointerTracker.setReleasedKeyGraphicsToAllKeys(); 701375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 702375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 7030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Background state set 7040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { 7050e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_MIDDLE 7060e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka EMPTY_STATE_SET, 7070e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_has_morekeys } 7080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }, 7090e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_LEFT 7100e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_left_edge }, 7110e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_left_edge, R.attr.state_has_morekeys } 7120e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }, 7130e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_RIGHT 7140e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_right_edge }, 7150e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_right_edge, R.attr.state_has_morekeys } 7160e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7170e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }; 7180e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_MIDDLE = 0; 7190e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_LEFT = 1; 7200e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_RIGHT = 2; 7210e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_NORMAL = 0; 7220e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_HAS_MOREKEYS = 1; 7230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7240e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 7250e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void showKeyPreview(final PointerTracker tracker) { 7260e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams; 7270e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 7280e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (!mShowKeyPreviewPopup) { 7290e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleOffset = -keyboard.mVerticalGap; 7300e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return; 7310e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7320e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7330e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final TextView previewText = getKeyPreviewText(tracker.mPointerId); 7340e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // If the key preview has no parent view yet, add it to the ViewGroup which can place 7350e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // key preview absolutely in SoftInputWindow. 7360e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (previewText.getParent() == null) { 7370e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka addKeyPreview(previewText); 7380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7390e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7400e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mDrawingHandler.cancelDismissKeyPreview(tracker); 7410e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Key key = tracker.getKey(); 7420e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // If key is invalid or IME is already closed, we must not show key preview. 7430e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Trying to show key preview while root window is closed causes 7440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // WindowManager.BadTokenException. 7450e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (key == null) { 7460e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return; 7470e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7490e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final KeyDrawParams drawParams = mKeyDrawParams; 7500e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setTextColor(drawParams.mPreviewTextColor); 7510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Drawable background = previewText.getBackground(); 752914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka final String label = key.getPreviewLabel(); 7530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // What we show as preview should match what we show on a key top in onDraw(). 7540e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (label != null) { 7550e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // TODO Should take care of temporaryShiftLabel here. 7560e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setCompoundDrawables(null, null, null, null); 757914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, 758914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka key.selectPreviewTextSize(drawParams)); 759914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka previewText.setTypeface(key.selectPreviewTypeface(drawParams)); 7600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setText(label); 7610e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 7620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setCompoundDrawables(null, null, null, 7630e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka key.getPreviewIcon(keyboard.mIconsSet)); 7640e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setText(null); 7650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7660e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7670e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.measure( 7680e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 7690e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int keyDrawWidth = key.getDrawWidth(); 7700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewWidth = previewText.getMeasuredWidth(); 7710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewHeight = mKeyPreviewHeight; 7720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The width and height of visible part of the key preview background. The content marker 7730e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // of the background 9-patch have to cover the visible part of the background. 7740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleWidth = previewWidth - previewText.getPaddingLeft() 7750e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka - previewText.getPaddingRight(); 7760e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleHeight = previewHeight - previewText.getPaddingTop() 7770e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka - previewText.getPaddingBottom(); 7780e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The distance between the top edge of the parent key and the bottom of the visible part 7790e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // of the key preview background. 7800e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleOffset = mKeyPreviewOffset - previewText.getPaddingBottom(); 7810e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka getLocationInWindow(mOriginCoords); 7820e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The key preview is horizontally aligned with the center of the visible part of the 7830e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and 7840e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // the left/right background is used if such background is specified. 7850e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int statePosition; 7860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 7870e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka + CoordinateUtils.x(mOriginCoords); 7880e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (previewX < 0) { 7890e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewX = 0; 7900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_LEFT; 7910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else if (previewX > getWidth() - previewWidth) { 7920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewX = getWidth() - previewWidth; 7930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_RIGHT; 7940e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 7950e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_MIDDLE; 7960e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7970e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The key preview is placed vertically above the top edge of the parent key with an 7980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // arbitrary offset. 7990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewY = key.mY - previewHeight + mKeyPreviewOffset 8000e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka + CoordinateUtils.y(mOriginCoords); 8010e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (background != null) { 8030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int hasMoreKeys = (key.mMoreKeys != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; 8040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); 8053201e986473f18ed13e1e3dad87c2ecde1d3edc8Tadashi G. Takaoka background.setAlpha(PREVIEW_ALPHA); 8060e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8070e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka ViewLayoutUtils.placeViewAt( 8080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText, previewX, previewY, previewWidth, previewHeight); 8090e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 8100e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8110e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8120e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8130e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void dismissKeyPreview(final PointerTracker tracker) { 8140e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, tracker); 8150e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8160e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 817ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka public void setSlidingKeyInputPreviewEnabled(final boolean enabled) { 818ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mSlidingKeyInputPreview.setPreviewEnabled(enabled); 819ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka } 820ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka 8210e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8220e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void showSlidingKeyInputPreview(final PointerTracker tracker) { 8230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka locatePreviewPlacerView(); 824fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview.setPreviewPosition(tracker); 8250e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8260e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8270e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8280e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void dismissSlidingKeyInputPreview() { 829fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview.dismissSlidingKeyInputPreview(); 8300e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8310e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 832cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa public void setGesturePreviewMode(final boolean drawsGestureTrail, 833375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final boolean drawsGestureFloatingPreviewText) { 834fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText.setPreviewEnabled(drawsGestureFloatingPreviewText); 835cb3bba3c4ee4652e12c81185ab9a648db20bb0ddKen Wakasa mGestureTrailsPreview.setPreviewEnabled(drawsGestureTrail); 836375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 837375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 838375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) { 839375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 840fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText.setSuggetedWords(suggestedWords); 841375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 842375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 843375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissGestureFloatingPreviewText() { 844375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 845375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mDrawingHandler.dismissGestureFloatingPreviewText(mGestureFloatingPreviewTextLingerTimeout); 846375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 847375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 848fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka @Override 849212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public void showGestureTrail(final PointerTracker tracker, 850212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka final boolean showsFloatingPreviewText) { 851375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 852212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka if (showsFloatingPreviewText) { 853212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mGestureFloatingPreviewText.setPreviewPosition(tracker); 854212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 855fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview.setPreviewPosition(tracker); 856375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 857375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 8588335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 859dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 8608335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable); 8618335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 8628335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 863dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 8648335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser); 8650657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka } 8660657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka 8675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 8684331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge protected void onAttachedToWindow() { 8694331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge super.onAttachedToWindow(); 8709c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Notify the ResearchLogger (development only diagnostics) that the keyboard view has 8719c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // been attached. This is needed to properly show the splash screen, which requires that 8729c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // the window token of the KeyboardView be non-null. 8739c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 874c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow(this); 875c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 876c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 877c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka 878c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka @Override 879c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka protected void onDetachedFromWindow() { 880c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka super.onDetachedFromWindow(); 881375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.removeAllViews(); 8829c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Notify the ResearchLogger (development only diagnostics) that the keyboard view has 8839c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // been detached. This is needed to invalidate the reference of {@link MainKeyboardView} 8849c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // to null. 8859c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 886c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onDetachedFromWindow(); 8874331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 8884331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 8894331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge 890a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) { 891a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (key.mMoreKeys == null) { 8925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return null; 89320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 894a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key); 895a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (moreKeysKeyboard == null) { 896a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka moreKeysKeyboard = new MoreKeysKeyboard.Builder( 897a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka context, key, this, mKeyPreviewDrawParams).build(); 898a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.put(key, moreKeysKeyboard); 89920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 9005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 901a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final View container = mMoreKeysKeyboardContainer; 9022affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka final MoreKeysKeyboardView moreKeysKeyboardView = 9032affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); 9042affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); 905b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 9062affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka return moreKeysKeyboardView; 9075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 9095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 910d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * Called when a key is long pressed. 9115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param tracker the pointer tracker which pressed the parent key 9125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 91396efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka private void onLongPress(final PointerTracker tracker) { 914a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 91596efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 916a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 917a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final Key key = tracker.getKey(); 918a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (key == null) { 91996efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 920a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 9219c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 922c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_onLongPress(); 9239bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 924f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final KeyboardActionListener listener = mKeyboardActionListener; 9259552badf3c24d2098d227b0ddca0721b928a10b1Tadashi G. Takaoka if (key.hasNoPanelAutoMoreKey()) { 926f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final int moreKeyCode = key.mMoreKeys[0].mCode; 9273708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka tracker.onLongPressed(); 9286455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka listener.onPressKey(moreKeyCode, false /* isRepeatKey */, true /* isSinglePointer */); 929f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onCodeInput(moreKeyCode, 930f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 931f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onReleaseKey(moreKeyCode, false /* withSliding */); 93296efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 9333708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka } 934f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final int code = key.mCode; 935a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) { 9363708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka // Long pressing the space key invokes IME switcher dialog. 937f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka if (listener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) { 9386dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 939f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onReleaseKey(code, false /* withSliding */); 94096efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 9416dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 9426dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 94396efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka openMoreKeysPanel(key, tracker); 9446dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 9456dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 94696efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka private void openMoreKeysPanel(final Key key, final PointerTracker tracker) { 947a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = onCreateMoreKeysPanel(key, getContext()); 9489d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (moreKeysPanel == null) { 94996efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 9505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 95163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 952547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 953547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.getLastCoordinates(lastCoords); 954a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !key.noKeyPreview(); 9557ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually horizontally aligned with the center of the parent key. 9567ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more 9577ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // keys keyboard is placed at the touch point of the parent key. 9587ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled) 959547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka ? CoordinateUtils.x(lastCoords) 960a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka : key.mX + key.mWidth / 2; 9617ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually vertically aligned with the top edge of the parent key 9627ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically 9637ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // aligned with the bottom edge of the visible part of the key preview. 96429d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@code mPreviewVisibleOffset} has been set appropriately in 96529d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@link KeyboardView#showKeyPreview(PointerTracker)}. 966a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int pointY = key.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset; 967fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); 968547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(CoordinateUtils.x(lastCoords)); 969547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(CoordinateUtils.y(lastCoords)); 970e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaoka tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); 9715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 9735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 974a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 97563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return true; 9765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 97720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return PointerTracker.isAnyInSlidingKeyInput(); 9785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 980d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 981d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public void onShowMoreKeysPanel(final MoreKeysPanel panel) { 9821b6eea89037158a1e271730eacdacb8b6e550d3aTadashi G. Takaoka locatePreviewPlacerView(); 9830e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka // TODO: Remove this check 9840e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka if (panel.isShowingInParent()) { 9850e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka panel.dismissMoreKeysPanel(); 986d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 987a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mPreviewPlacerView.addView(panel.getContainerView()); 988d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMoreKeysPanel = panel; 989a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka dimEntireKeyboard(true /* dimmed */); 990d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 991d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 992d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public boolean isShowingMoreKeysPanel() { 993a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return mMoreKeysPanel != null && mMoreKeysPanel.isShowingInParent(); 994d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 995d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 996d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 9970e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { 998d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka PointerTracker.dismissAllMoreKeysPanels(); 999d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1000d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 1001d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 10020e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { 1003d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka dimEntireKeyboard(false /* dimmed */); 1004d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 1005d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mPreviewPlacerView.removeView(mMoreKeysPanel.getContainerView()); 1006d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMoreKeysPanel = null; 1007d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1008d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1009d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 10105433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka public void startDoubleTapShiftKeyTimer() { 10115433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka mKeyTimerHandler.startDoubleTapShiftKeyTimer(); 10125433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka } 10135433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 10145433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka public void cancelDoubleTapShiftKeyTimer() { 10155433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka mKeyTimerHandler.cancelDoubleTapShiftKeyTimer(); 10165433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka } 10175433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 10185433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka public boolean isInDoubleTapShiftKeyTimeout() { 10195433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka return mKeyTimerHandler.isInDoubleTapShiftKeyTimeout(); 10205433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka } 10215433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 10225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 1023dc2ee7772402633817702e95c2a5b17f6dec03ebalanv public boolean dispatchTouchEvent(MotionEvent event) { 1024dc2ee7772402633817702e95c2a5b17f6dec03ebalanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 1025dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return AccessibleKeyboardViewProxy.getInstance().dispatchTouchEvent(event); 1026dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 1027dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return super.dispatchTouchEvent(event); 1028dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 1029dc2ee7772402633817702e95c2a5b17f6dec03ebalanv 1030dc2ee7772402633817702e95c2a5b17f6dec03ebalanv @Override 1031dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean onTouchEvent(final MotionEvent me) { 103246286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka if (getKeyboard() == null) { 103346286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka return false; 103446286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka } 1035310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka // TODO: Add multi-touch to single-touch event converter for non-distinct multi-touch 1036310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka // device. 1037310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka return processMotionEvent(me); 1038c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 1039c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 1040dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean processMotionEvent(final MotionEvent me) { 1041f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final boolean nonDistinctMultitouch = !mHasDistinctMultitouch; 10425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int action = me.getActionMasked(); 10435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int pointerCount = me.getPointerCount(); 10445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int oldPointerCount = mOldPointerCount; 10455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mOldPointerCount = pointerCount; 10465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 10485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // If the device does not have distinct multi-touch support panel, ignore all multi-touch 10495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // events except a transition from/to single-touch. 1050f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) { 10515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 10525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final long eventTime = me.getEventTime(); 10555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int index = me.getActionIndex(); 10565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int id = me.getPointerId(index); 105735580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int x = (int)me.getX(index); 105835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int y = (int)me.getY(index); 105935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 1060fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // TODO: This might be moved to the tracker.processMotionEvent() call below. 106130977a151e15e30f5385a349e92fb770b987435fTadashi G. Takaoka if (LatinImeLogger.sUsabilityStudy) { 106230977a151e15e30f5385a349e92fb770b987435fTadashi G. Takaoka UsabilityStudyLogUtils.writeMotionEvent(me); 1063d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 1064fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // TODO: This should be moved to the tracker.processMotionEvent() call below. 1065fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // Currently the same "move" event is being logged twice. 10669c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 1067fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka ResearchLogger.mainKeyboardView_processMotionEvent( 1068fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka me, action, eventTime, index, id, x, y); 106915d4793911fa305e0a58aced925961e948582979satok } 10705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1071f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (mKeyTimerHandler.isInKeyRepeat()) { 1072e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 10735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Key repeating timer will be canceled if 2 or more keys are in action, and current 10745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // event (UP or DOWN) is non-modifier key. 10755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount > 1 && !tracker.isModifier()) { 1076f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelKeyRepeatTimer(); 10775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Up event will pass through. 10795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 10825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Translate mutli-touch event to single-touch events on the device that has no distinct 10835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // multi-touch panel. 1084f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch) { 10855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Use only main (id=0) pointer tracker. 1086e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 10875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount == 1 && oldPointerCount == 2) { 10885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Multi-touch to single touch transition. 10895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send a down event for the latest pointer if the key is different from the 10905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // previous key. 1091e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key newKey = tracker.getKeyOn(x, y); 1092e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (mOldKey != newKey) { 10930efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka tracker.onDownEvent(x, y, eventTime, this); 1094fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka if (action == MotionEvent.ACTION_UP) { 1095906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka tracker.onUpEvent(x, y, eventTime); 1096fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 10975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 2 && oldPointerCount == 1) { 10995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Single-touch to multi-touch transition. 11005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send an up event for the last pointer. 1101547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 1102547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka mOldKey = tracker.getKeyOn( 1103547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords)); 1104547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.onUpEvent( 1105547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime); 11065f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 1 && oldPointerCount == 1) { 11078ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 11085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 11095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount 11105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka + " (old " + oldPointerCount + ")"); 11115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 11135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (action == MotionEvent.ACTION_MOVE) { 11165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka for (int i = 0; i < pointerCount; i++) { 1117d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final int pointerId = me.getPointerId(i); 1118e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker( 1119d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge pointerId, this); 112035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int px = (int)me.getX(i); 112135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int py = (int)me.getY(i); 112235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang tracker.onMoveEvent(px, py, eventTime, me); 11235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 1125e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 1126e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 11275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 11305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11325c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka public void cancelAllOngoingEvents() { 1133375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyTimerHandler.cancelAllMessages(); 1134375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mDrawingHandler.cancelAllMessages(); 11355c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissAllKeyPreviews(); 11365c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissGestureFloatingPreviewText(); 11375c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissSlidingKeyInputPreview(); 11385c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka PointerTracker.dismissAllMoreKeysPanels(); 11395c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka PointerTracker.cancelAllPointerTrackers(); 1140375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 1141375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 11425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void closing() { 11435c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka cancelAllOngoingEvents(); 1144a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.clear(); 11455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1147586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette /** 1148c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka * Receives hover events from the input framework. 1149586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * 1150586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @param event The motion event to be dispatched. 1151586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @return {@code true} if the event was handled by the view, {@code false} 1152586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * otherwise 1153586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette */ 1154c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka @Override 1155dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean dispatchHoverEvent(final MotionEvent event) { 11565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 1157e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 1158586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker); 11595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1161586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette // Reflection doesn't support calling superclass methods. 11625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 11635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 116422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 1165dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateShortcutKey(final boolean available) { 11667bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 116720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (keyboard == null) { 116820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 116920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1170240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT); 117120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (shortcutKey == null) { 117220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 117320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 11747bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka shortcutKey.setEnabled(available); 11757bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka invalidateKey(shortcutKey); 11765afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka } 11775afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka 1178dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, 1179dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final boolean needsToDisplayLanguage, final boolean hasMultipleEnabledIMEsOrSubtypes) { 11804112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mNeedsToDisplayLanguage = needsToDisplayLanguage; 1181fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; 1182fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; 1183d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator == null) { 1184aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka mNeedsToDisplayLanguage = false; 11854c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } else { 1186dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka if (subtypeChanged && needsToDisplayLanguage) { 11874daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); 118831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (animator.isStarted()) { 118931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.cancel(); 119031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 1191d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka animator.start(); 1192dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } else { 119331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (!animator.isStarted()) { 119431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha; 119531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 1196dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } 11974c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } 11984112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 11994112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 12004112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1201dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateAutoCorrectionState(final boolean isAutoCorrection) { 120220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (!mAutoCorrectionSpacebarLedEnabled) { 120320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 120420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 12054112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedOn = isAutoCorrection; 12064112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 120722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 120822b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 1209a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private void dimEntireKeyboard(final boolean dimmed) { 1210f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka final boolean needsRedrawing = mNeedsToDimEntireKeyboard != dimmed; 1211f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mNeedsToDimEntireKeyboard = dimmed; 1212f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka if (needsRedrawing) { 1213f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka invalidateAllKeys(); 1214f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1215f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1216f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 1217f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka @Override 1218f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka protected void onDraw(final Canvas canvas) { 1219f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka super.onDraw(canvas); 1220f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 1221f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka // Overlay a dark rectangle to dim. 1222f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka if (mNeedsToDimEntireKeyboard) { 122308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mBackgroundDimAlphaPaint); 1224f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1225f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1226f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 122722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka @Override 1228dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, 1229dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final KeyDrawParams params) { 12306bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.altCodeWhileTyping() && key.isEnabled()) { 123173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha; 123273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 1233240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (key.mCode == Constants.CODE_SPACE) { 1234bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawSpacebar(key, canvas, paint); 12354112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Whether space key needs to show the "..." popup hint for special purposes 1236fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) { 1237bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 12384112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 1239240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (key.mCode == Constants.CODE_LANGUAGE_SWITCH) { 124081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 1241fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 1242b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka } else { 1243b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 124422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 124522b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 12464112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 124708ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka private static boolean fitsTextIntoWidth(final int width, final String text, 124808ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final Paint paint) { 1249bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(1.0f); 125008ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final float textWidth = TypefaceUtils.getLabelWidth(text, paint); 125120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (textWidth < width) { 125220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return true; 125320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1254bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1255bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final float scaleX = width / textWidth; 125620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) { 125720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return false; 125820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1259bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1260bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(scaleX); 126108ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka return TypefaceUtils.getLabelWidth(text, paint) < width; 1262bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 1263bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1264bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Layout language name on spacebar. 126508ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka private static String layoutLanguageOnSpacebar(final Paint paint, 126608ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final InputMethodSubtype subtype, final int width) { 1267bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Choose appropriate language name to fit into the width. 1268a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String fullText = SubtypeLocaleUtils.getFullDisplayName(subtype); 126920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, fullText, paint)) { 127020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return fullText; 1271bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 1272bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1273a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String middleText = SubtypeLocaleUtils.getMiddleDisplayName(subtype); 127420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, middleText, paint)) { 127520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return middleText; 12764112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 12774112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1278a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String shortText = SubtypeLocaleUtils.getShortDisplayName(subtype); 127920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, shortText, paint)) { 128020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return shortText; 12814112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 12824112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1283bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return ""; 12844112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 12854112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1286dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void drawSpacebar(final Key key, final Canvas canvas, final Paint paint) { 1287bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka final int width = key.mWidth; 1288b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final int height = key.mHeight; 12894112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1290f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka // If input language are explicitly selected. 1291bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mNeedsToDisplayLanguage) { 1292bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextAlign(Align.CENTER); 1293bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTypeface(Typeface.DEFAULT); 1294bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextSize(mSpacebarTextSize); 1295bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final InputMethodSubtype subtype = getKeyboard().mId.mSubtype; 1296bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final String language = layoutLanguageOnSpacebar(paint, subtype, width); 12974112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw language text with shadow 12984112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float descent = paint.descent(); 12994112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float textHeight = -paint.ascent() + descent; 1300b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final float baseline = height / 2 + textHeight / 2; 1301aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextShadowColor); 130231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 13034112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent - 1, paint); 1304aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextColor); 130531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 13064112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent, paint); 13074112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13084112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 13094112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw the spacebar icon at the bottom 1310bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mAutoCorrectionSpacebarLedOn) { 13114112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; 13124112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); 13134112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 13144112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1315bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight); 13164112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } else if (mSpaceIcon != null) { 13174112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = mSpaceIcon.getIntrinsicWidth(); 13184112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mSpaceIcon.getIntrinsicHeight(); 13194112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 13204112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1321bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight); 13224112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13234112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 1324c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa 1325c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa public void deallocateMemory() { 1326c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa mGestureTrailsPreview.deallocateMemory(); 1327c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa } 13285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka} 1329