MainKeyboardView.java revision 57372fd3da2e879f190e4ccd41a00813774c9019
15f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/* 25f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project 35f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 45f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 55f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * you may not use this file except in compliance with the License. 65f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * You may obtain a copy of the License at 75f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 85f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 95f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * See the License for the specific language governing permissions and 145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * limitations under the License. 155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 19d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaokaimport android.animation.AnimatorInflater; 2031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaokaimport android.animation.ObjectAnimator; 215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.Context; 2213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport android.content.SharedPreferences; 235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.pm.PackageManager; 2427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport android.content.res.Resources; 254112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.content.res.TypedArray; 266dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport android.graphics.Canvas; 27f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaokaimport android.graphics.Color; 2822b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaokaimport android.graphics.Paint; 294112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.Paint.Align; 30bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaokaimport android.graphics.Typeface; 314112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.drawable.Drawable; 325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.os.Message; 3372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaokaimport android.os.SystemClock; 3413ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport android.preference.PreferenceManager; 355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.AttributeSet; 36375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport android.util.DisplayMetrics; 375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.Log; 38375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport android.util.SparseArray; 390e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport android.util.TypedValue; 405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.LayoutInflater; 415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.MotionEvent; 425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.View; 435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.ViewConfiguration; 44b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaokaimport android.view.ViewGroup; 45f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 460e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport android.widget.TextView; 475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 5015f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.ExternallyReferenced; 51f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; 522321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.TimerProxy; 53fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureFloatingPreviewText; 54fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureTrailsPreview; 5549d8af8a4e900f3c68c333aba7fde0a11fd368b1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyDrawParams; 560e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; 57375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PreviewPlacerView; 58fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.SlidingKeyInputPreview; 59081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.TouchScreenRegulator; 60375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils; 614daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport com.android.inputmethod.latin.Constants; 62547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaokaimport com.android.inputmethod.latin.CoordinateUtils; 6313ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport com.android.inputmethod.latin.DebugSettings; 646dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinIME; 6515d4793911fa305e0a58aced925961e948582979satokimport com.android.inputmethod.latin.LatinImeLogger; 665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 679879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils; 68cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaokaimport com.android.inputmethod.latin.Settings; 695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.StaticInnerHandlerWrapper; 7027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport com.android.inputmethod.latin.StringUtils; 713bf57a5624679a20db26df912077a53b9f90ad36Tadashi G. Takaokaimport com.android.inputmethod.latin.SubtypeLocale; 72375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords; 7315d4793911fa305e0a58aced925961e948582979satokimport com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; 74c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 756b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaokaimport java.util.Locale; 785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap; 795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/** 815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements. 825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 83dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedEnabled 84dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedIcon 85dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextRatio 86dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextColor 87dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_spacebarTextShadowColor 88dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha 89dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFadeoutAnimator 90dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator 91dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator 92dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyHysteresisDistance 93dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdTime 94dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdDistance 95dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_slidingKeyInputEnable 96dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatStartTimeout 97dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatInterval 98dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressKeyTimeout 99dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout 100dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout 101375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLayout 1020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewOffset 1030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewHeight 1040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLingerTimeout 105d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardLayout 106f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_backgroundDimAlpha 107dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint 108375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureFloatingPreviewTextLingerTimeout 1093623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping 1103623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDetectFastMoveSpeedThreshold 1113623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicThresholdDecayDuration 1123623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdFrom 1133623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdTo 1143623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdFrom 1153623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdTo 1163623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureSamplingMinimumDistance 1173623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionMinimumTime 1183623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold 1193623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration 1205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 121a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class MainKeyboardView extends KeyboardView implements PointerTracker.KeyEventHandler, 1220e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka PointerTracker.DrawingProxy, MoreKeysPanel.Controller, 1230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka TouchScreenRegulator.ProcessMotionEvent { 124c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka private static final String TAG = MainKeyboardView.class.getSimpleName(); 1255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 126d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge // TODO: Kill process when the usability study mode was changed. 127d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy; 128d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge 129bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /** Listener for {@link KeyboardActionListener}. */ 130bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private KeyboardActionListener mKeyboardActionListener; 131bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka 132bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /* Space key and its icons */ 1334112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Key mSpaceKey; 1344112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Drawable mSpaceIcon; 135bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw language name on spacebar. 13631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private final int mLanguageOnSpacebarFinalAlpha; 13731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; 138bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mNeedsToDisplayLanguage; 139fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka private boolean mHasMultipleEnabledIMEsOrSubtypes; 1404daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; 1414112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final float mSpacebarTextRatio; 1424112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private float mSpacebarTextSize; 1434112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextColor; 1444112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private final int mSpacebarTextShadowColor; 145bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // The minimum x-scale to fit the language name on spacebar. 146bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f; 147bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw auto correction LED on spacebar. 148bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mAutoCorrectionSpacebarLedOn; 149bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final boolean mAutoCorrectionSpacebarLedEnabled; 150bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final Drawable mAutoCorrectionSpacebarLedIcon; 151bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private static final int SPACE_LED_LENGTH_PERCENT = 80; 15215d4793911fa305e0a58aced925961e948582979satok 15373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka // Stuff to draw altCodeWhileTyping keys. 15431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; 15531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; 1564daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; 15773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 158375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Preview placer view 159375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final PreviewPlacerView mPreviewPlacerView; 160375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final int[] mOriginCoords = CoordinateUtils.newInstance(); 161fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final GestureFloatingPreviewText mGestureFloatingPreviewText; 162fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final GestureTrailsPreview mGestureTrailsPreview; 163fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final SlidingKeyInputPreview mSlidingKeyInputPreview; 164375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 1650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Key preview 1660e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int PREVIEW_ALPHA = 240; 167375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final int mKeyPreviewLayoutId; 1680e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final int mKeyPreviewOffset; 1690e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final int mKeyPreviewHeight; 170375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final SparseArray<TextView> mKeyPreviewTexts = CollectionUtils.newSparseArray(); 1710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); 1720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private boolean mShowKeyPreviewPopup = true; 1730e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private int mKeyPreviewLingerTimeout; 1740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 1752affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka // More keys keyboard 176f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka private final Paint mBackgroundDimAlphaPaint = new Paint(); 177f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka private boolean mNeedsToDimEntireKeyboard; 178a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private final View mMoreKeysKeyboardContainer; 179a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = 180a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka CollectionUtils.newWeakHashMap(); 1812affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint; 182d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka // More keys panel (used by both more keys keyboard and more suggestions view) 183d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka // TODO: Consider extending to support multiple more keys panels 184d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka private MoreKeysPanel mMoreKeysPanel; 1855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 186375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Gesture floating preview text 187375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // TODO: Make this parameter customizable by user via settings. 188375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private int mGestureFloatingPreviewTextLingerTimeout; 189375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 190081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaoka private final TouchScreenRegulator mTouchScreenRegulator; 1915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 192d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka private KeyDetector mKeyDetector; 19313ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka private final boolean mHasDistinctMultitouch; 1945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private int mOldPointerCount = 1; 195e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mOldKey; 1965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 197160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka private final KeyTimerHandler mKeyTimerHandler; 1985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 199a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka private static final class KeyTimerHandler extends StaticInnerHandlerWrapper<MainKeyboardView> 2002321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka implements TimerProxy { 20127e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_TYPING_STATE_EXPIRED = 0; 202f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_REPEAT_KEY = 1; 203f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_LONGPRESS_KEY = 2; 2040ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka private static final int MSG_DOUBLE_TAP = 3; 20572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private static final int MSG_UPDATE_BATCH_INPUT = 4; 2065f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2075509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mKeyRepeatStartTimeout; 2085509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mKeyRepeatInterval; 209cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka private final int mLongPressShiftLockTimeout; 2105509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka private final int mIgnoreAltCodeKeyTimeout; 21172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka private final int mGestureRecognitionUpdateTime; 2125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2135509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka public KeyTimerHandler(final MainKeyboardView outerInstance, 2145509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka final TypedArray mainKeyboardViewAttr) { 2155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(outerInstance); 2165509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka 2175509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt( 2185509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0); 2195509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mKeyRepeatInterval = mainKeyboardViewAttr.getInt( 2205509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_keyRepeatInterval, 0); 221cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka mLongPressShiftLockTimeout = mainKeyboardViewAttr.getInt( 222cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka R.styleable.MainKeyboardView_longPressShiftLockTimeout, 0); 2235509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( 2245509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); 22572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt( 22672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0); 2275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 230dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void handleMessage(final Message msg) { 231c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 23248d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka if (keyboardView == null) { 23348d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka return; 23448d8d8d0ae573605f938b3859bf58e1972f0d737Tadashi G. Takaoka } 2355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 2365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka switch (msg.what) { 23727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka case MSG_TYPING_STATE_EXPIRED: 23827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 23927e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka break; 2405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_REPEAT_KEY: 2418a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key currentKey = tracker.getKey(); 2428a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka if (currentKey != null && currentKey.mCode == msg.arg1) { 2438a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka tracker.onRegisterKey(currentKey); 2445509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka startKeyRepeatTimer(tracker, mKeyRepeatInterval); 2458a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka } 2465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 2475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_LONGPRESS_KEY: 248a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka if (tracker != null) { 249a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka keyboardView.onLongPress(tracker); 250a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } else { 251a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1); 252a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 2535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 25472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka case MSG_UPDATE_BATCH_INPUT: 25572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka tracker.updateBatchInputByTimer(SystemClock.uptimeMillis()); 25672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka startUpdateBatchInputTimer(tracker); 25772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka break; 2585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 261dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void startKeyRepeatTimer(final PointerTracker tracker, final long delay) { 2628a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka final Key key = tracker.getKey(); 26320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (key == null) { 26420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 26520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 2668a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, key.mCode, 0, tracker), delay); 26732c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka } 26832c54c4dbed0b27b7177f796d90a2ebb9566c9c9Tadashi G. Takaoka 2692321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 270dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startKeyRepeatTimer(final PointerTracker tracker) { 2715509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka startKeyRepeatTimer(tracker, mKeyRepeatStartTimeout); 2725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelKeyRepeatTimer() { 2755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_REPEAT_KEY); 2765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2780d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka // TODO: Suppress layout changes in key repeat mode 2795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInKeyRepeat() { 2800d9d37cec2b3c4b4c3747baeb529bd2a70cbafb8Tadashi G. Takaoka return hasMessages(MSG_REPEAT_KEY); 2815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2832321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 284dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startLongPressTimer(final int code) { 28598b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka cancelLongPressTimer(); 286a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka final int delay; 287a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka switch (code) { 288240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHIFT: 289cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka delay = mLongPressShiftLockTimeout; 290a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka break; 291a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka default: 292a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka delay = 0; 293a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka break; 294a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 295a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka if (delay > 0) { 296a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, code, 0), delay); 297a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 298a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 299a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka 300a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka @Override 301dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startLongPressTimer(final PointerTracker tracker) { 302a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka cancelLongPressTimer(); 3037b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (tracker == null) { 3047b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka return; 3057b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } 3067b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka final Key key = tracker.getKey(); 3077b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka final int delay; 3087b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka switch (key.mCode) { 309240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHIFT: 310cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka delay = mLongPressShiftLockTimeout; 3117b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka break; 3127b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka default: 313cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka final int longpressTimeout = 314cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka Settings.getInstance().getCurrent().mKeyLongpressTimeout; 3157b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (KeyboardSwitcher.getInstance().isInMomentarySwitchState()) { 3167b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka // We use longer timeout for sliding finger input started from the symbols 3177b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka // mode key. 318cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka delay = longpressTimeout * 3; 3197b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } else { 320cc5e4a444524f73a112d7223d7940d41cf60d1f4Tadashi G. Takaoka delay = longpressTimeout; 321a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 3227b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka break; 3237b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka } 3247b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka if (delay > 0) { 3257b6afb1287fb6d5edfebed7403eb31ed23a8348dTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, tracker), delay); 326a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka } 3275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3292321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 33098b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer() { 3315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_LONGPRESS_KEY); 3325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 334d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, 33545213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final ObjectAnimator animatorToStart) { 33657372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka if (animatorToCancel == null || animatorToStart == null) { 33757372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka // TODO: Stop using null as a no-operation animator. 33857372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka return; 33957372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka } 34045213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka float startFraction = 0.0f; 34145213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka if (animatorToCancel.isStarted()) { 342b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka animatorToCancel.cancel(); 34345213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka startFraction = 1.0f - animatorToCancel.getAnimatedFraction(); 344b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 34545213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka final long startTime = (long)(animatorToStart.getDuration() * startFraction); 34645213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.start(); 34745213ed2a6e9a940ec540ff43ded7e877cb20dc9Tadashi G. Takaoka animatorToStart.setCurrentPlayTime(startTime); 348b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka } 349b9720a55b47684589e3176434cd2b1a08942d112Tadashi G. Takaoka 350d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeinAnimation(final MainKeyboardView keyboardView) { 351d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator, 352d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeinAnimator); 353d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 354d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 355d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka private static void startWhileTypingFadeoutAnimation(final MainKeyboardView keyboardView) { 356d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka cancelAndStartAnimators(keyboardView.mAltCodeKeyWhileTypingFadeinAnimator, 357d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka keyboardView.mAltCodeKeyWhileTypingFadeoutAnimator); 358d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 359d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 3602321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 361dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startTypingStateTimer(final Key typedKey) { 362d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { 363d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 364d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 365d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 36673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final boolean isTyping = isTypingState(); 367f1678ba8024606349bc184cfeaead2be059f7b5bTadashi G. Takaoka removeMessages(MSG_TYPING_STATE_EXPIRED); 368d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final MainKeyboardView keyboardView = getOuterInstance(); 369d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 370d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka // When user hits the space or the enter key, just cancel the while-typing timer. 371d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka final int typedCode = typedKey.mCode; 372240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) { 373d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka startWhileTypingFadeinAnimation(keyboardView); 374d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka return; 375d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka } 376d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka 37773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka sendMessageDelayed( 3785509798977a61dcb4a9dde9030f31bb138b71e3bTadashi G. Takaoka obtainMessage(MSG_TYPING_STATE_EXPIRED), mIgnoreAltCodeKeyTimeout); 37973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (isTyping) { 38073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return; 38173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 382d2173b5737bf791a65f6b1e2980f26ebd94369c5Tadashi G. Takaoka startWhileTypingFadeoutAnimation(keyboardView); 38393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 38493246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 38593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka @Override 38673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka public boolean isTypingState() { 38773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka return hasMessages(MSG_TYPING_STATE_EXPIRED); 38893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka } 38993246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka 3909f09c6fbc81ed40a41c0a23bd5913214ec7f6a9bTadashi G. Takaoka @Override 3910ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void startDoubleTapTimer() { 3920ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP), 3935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka ViewConfiguration.getDoubleTapTimeout()); 3945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3960ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka @Override 397beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void cancelDoubleTapTimer() { 398beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka removeMessages(MSG_DOUBLE_TAP); 399beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka } 400beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 401beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka @Override 4020ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public boolean isInDoubleTapTimeout() { 4030ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka return hasMessages(MSG_DOUBLE_TAP); 4045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 405c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 406c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka @Override 4070ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelKeyTimers() { 4080ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyRepeatTimer(); 4090ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelLongPressTimer(); 410c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 411c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 41272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 41372fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka public void startUpdateBatchInputTimer(final PointerTracker tracker) { 41472fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka if (mGestureRecognitionUpdateTime <= 0) { 41572fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka return; 41672fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 41772fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 41872fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_BATCH_INPUT, tracker), 41972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka mGestureRecognitionUpdateTime); 42072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 42172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 42272fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka @Override 423915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka public void cancelUpdateBatchInputTimer(final PointerTracker tracker) { 424915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 425915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka } 426915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka 427915f348b35cb66ed9696a51c9250f9b25799fb82Tadashi G. Takaoka @Override 4282db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka public void cancelAllUpdateBatchInputTimers() { 42972fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka removeMessages(MSG_UPDATE_BATCH_INPUT); 43072fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka } 43172fd0968e5227ffc383b1f9d096872ba39cfdce8Tadashi G. Takaoka 4320ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka public void cancelAllMessages() { 4330ed2d3a4491cb0f6142975a15b653be6079b6a4eTadashi G. Takaoka cancelKeyTimers(); 4342db9e1c447a71f0aec3067697cf294f711a9e4e0Tadashi G. Takaoka cancelAllUpdateBatchInputTimers(); 435c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 436c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 437c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 438375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final DrawingHandler mDrawingHandler = new DrawingHandler(this); 439375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 440375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public static class DrawingHandler extends StaticInnerHandlerWrapper<MainKeyboardView> { 441375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private static final int MSG_DISMISS_KEY_PREVIEW = 0; 442375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; 443375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 444375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public DrawingHandler(final MainKeyboardView outerInstance) { 445375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka super(outerInstance); 446375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 447375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 448375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka @Override 449375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void handleMessage(final Message msg) { 450375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final MainKeyboardView mainKeyboardView = getOuterInstance(); 451375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mainKeyboardView == null) return; 452375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 453375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka switch (msg.what) { 454375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka case MSG_DISMISS_KEY_PREVIEW: 455375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final TextView previewText = mainKeyboardView.mKeyPreviewTexts.get( 456375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka tracker.mPointerId); 457375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 458375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText.setVisibility(INVISIBLE); 459375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 460375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka break; 461375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: 462fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mainKeyboardView.showGestureFloatingPreviewText(SuggestedWords.EMPTY); 463375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka break; 464375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 465375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 466375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 467375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissKeyPreview(final long delay, final PointerTracker tracker) { 468375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, tracker), delay); 469375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 470375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 471375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void cancelDismissKeyPreview(final PointerTracker tracker) { 472375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka removeMessages(MSG_DISMISS_KEY_PREVIEW, tracker); 473375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 474375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 475375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void cancelAllDismissKeyPreviews() { 476375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka removeMessages(MSG_DISMISS_KEY_PREVIEW); 477375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 478375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 479375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissGestureFloatingPreviewText(final long delay) { 480375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay); 481375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 482375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 483375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void cancelAllMessages() { 484375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka cancelAllDismissKeyPreviews(); 485375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 486375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 487375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 488dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs) { 489c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka this(context, attrs, R.attr.mainKeyboardViewStyle); 4905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 492dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { 4935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(context, attrs, defStyle); 4945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 495081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaoka mTouchScreenRegulator = new TouchScreenRegulator(context, this); 496c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 49713ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 49813ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean forceNonDistinctMultitouch = prefs.getBoolean( 499a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false); 50013ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean hasDistinctMultitouch = context.getPackageManager() 5015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); 50213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka mHasDistinctMultitouch = hasDistinctMultitouch && !forceNonDistinctMultitouch; 503918e420d1becc1389b9895538eceff85fe882c99Tadashi G. Takaoka final Resources res = getResources(); 504d438fcaca2a35ace4fee5b7a469596bfe2d1b025Tadashi G. Takaoka final boolean needsPhantomSuddenMoveEventHack = Boolean.parseBoolean( 505fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka ResourceUtils.getDeviceOverrideValue( 506fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka res, R.array.phantom_sudden_move_event_device_list)); 50793b5c2ce63705e7ebffd9bdb7358100e8d5b5235Tadashi G. Takaoka PointerTracker.init(needsPhantomSuddenMoveEventHack); 508fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView = new PreviewPlacerView(context, attrs); 50922b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 510d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes( 511c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView); 512f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka final int backgroundDimAlpha = mainKeyboardViewAttr.getInt( 513f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka R.styleable.MainKeyboardView_backgroundDimAlpha, 0); 514f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mBackgroundDimAlphaPaint.setColor(Color.BLACK); 515f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha); 516d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mAutoCorrectionSpacebarLedEnabled = mainKeyboardViewAttr.getBoolean( 517c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false); 518d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mAutoCorrectionSpacebarLedIcon = mainKeyboardViewAttr.getDrawable( 519c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedIcon); 520d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextRatio = mainKeyboardViewAttr.getFraction( 521ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextRatio, 1, 1, 1.0f); 522d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextColor = mainKeyboardViewAttr.getColor( 523d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextColor, 0); 524d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mSpacebarTextShadowColor = mainKeyboardViewAttr.getColor( 525c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_spacebarTextShadowColor, 0); 526d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt( 527c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha, 5284daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang Constants.Color.ALPHA_OPAQUE); 529d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int languageOnSpacebarFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId( 530c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0); 531d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId( 532c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0); 533d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeinAnimatorResId = mainKeyboardViewAttr.getResourceId( 534c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); 535160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 536d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension( 53708ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f); 538d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension( 53908ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f); 540f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka mKeyDetector = new KeyDetector( 541f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier); 542d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mKeyTimerHandler = new KeyTimerHandler(this, mainKeyboardViewAttr); 5430e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewOffset = mainKeyboardViewAttr.getDimensionPixelOffset( 5440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewOffset, 0); 5450e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize( 5460e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewHeight, 0); 5470e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewLingerTimeout = mainKeyboardViewAttr.getInt( 5480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); 549375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyPreviewLayoutId = mainKeyboardViewAttr.getResourceId( 550375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewLayout, 0); 5510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (mKeyPreviewLayoutId == 0) { 5520e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mShowKeyPreviewPopup = false; 5530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 554a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( 555d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); 556d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( 557c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false); 558375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 559375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mGestureFloatingPreviewTextLingerTimeout = mainKeyboardViewAttr.getInt( 560375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); 561d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka PointerTracker.setParameters(mainKeyboardViewAttr); 562fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 563fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText = new GestureFloatingPreviewText( 564fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 565fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mGestureFloatingPreviewText); 566fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 567fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview = new GestureTrailsPreview( 568fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 569fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mGestureTrailsPreview); 570fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 571fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview = new SlidingKeyInputPreview( 572fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 573fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mSlidingKeyInputPreview); 574d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mainKeyboardViewAttr.recycle(); 575160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 576a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardContainer = LayoutInflater.from(getContext()) 577a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka .inflate(moreKeysKeyboardLayoutId, null); 57831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator( 57931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka languageOnSpacebarFadeoutAnimatorResId, this); 58031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator( 58131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeoutAnimatorResId, this); 58231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator( 58331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeinAnimatorResId, this); 58431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 58531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 586dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private ObjectAnimator loadObjectAnimator(final int resId, final Object target) { 58720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (resId == 0) { 58857372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka // TODO: Stop returning null. 58920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return null; 59020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 59131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator( 59231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka getContext(), resId); 593d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator != null) { 59431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.setTarget(target); 59573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 59631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return animator; 59731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 59873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 59915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 60031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getLanguageOnSpacebarAnimAlpha() { 60131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mLanguageOnSpacebarAnimAlpha; 602d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka } 603d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka 60415f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 605dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setLanguageOnSpacebarAnimAlpha(final int alpha) { 60631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = alpha; 60731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka invalidateKey(mSpaceKey); 60831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 60931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 61015f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 61131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getAltCodeKeyWhileTypingAnimAlpha() { 61231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mAltCodeKeyWhileTypingAnimAlpha; 61331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 61431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 61515f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 616dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) { 61731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingAnimAlpha = alpha; 61831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka updateAltCodeKeyWhileTyping(); 6195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 621dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboardActionListener(final KeyboardActionListener listener) { 6225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyboardActionListener = listener; 6235c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.setKeyboardActionListener(listener); 6245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 6275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns the {@link KeyboardActionListener} object. 6285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return the listener attached to this keyboard 6295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 6300efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 6310efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener() { 6325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mKeyboardActionListener; 6335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 635bb4be5444b845655c0eb80bcfbb66f93603802eaTadashi G. Takaoka @Override 6360efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyDetector getKeyDetector() { 6370efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyDetector; 6380efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 6390efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 6400efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 641f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy() { 642f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka return this; 643f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 644f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 645f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka @Override 6460efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public TimerProxy getTimerProxy() { 6470efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyTimerHandler; 6480efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 6490efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 6505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 6515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Attaches a keyboard to this view. The keyboard can be switched at any time and the 6525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * view will re-layout itself to accommodate the keyboard. 6535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see Keyboard 6545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see #getKeyboard() 6555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param keyboard the keyboard to display in this view 6565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 6575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 658dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboard(final Keyboard keyboard) { 6598a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka // Remove any pending messages, except dismissing preview and key repeat. 6608a092b4ede02b79422deae51f0a416b034777fb3Tadashi G. Takaoka mKeyTimerHandler.cancelLongPressTimer(); 6615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.setKeyboard(keyboard); 6625a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyDetector.setKeyboard( 66308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection()); 6648335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setKeyDetector(mKeyDetector); 665081fedc42269845a31e962b2ac1aa017b3a2efeeTadashi G. Takaoka mTouchScreenRegulator.setKeyboardGeometry(keyboard.mOccupiedWidth); 666a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.clear(); 6674112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 668240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka mSpaceKey = keyboard.getKey(Constants.CODE_SPACE); 6691f2d0aa6c9b343848ee51e5bc13ccaaadf3ba4feTadashi G. Takaoka mSpaceIcon = (mSpaceKey != null) 6704daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; 6714112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; 6724112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mSpacebarTextSize = keyHeight * mSpacebarTextRatio; 6739c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 674c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_setKeyboard(keyboard); 67548a7681e064ae259b840f0e757da2d716043d893Kurt Partridge } 676f147794fd41491a3383e6aca6d49007f58124068alanv 677f147794fd41491a3383e6aca6d49007f58124068alanv // This always needs to be set since the accessibility state can 678f147794fd41491a3383e6aca6d49007f58124068alanv // potentially change without the keyboard being set again. 679b6ca354431367b625daf9fff5fbe4b1f5ef996abKen Wakasa AccessibleKeyboardViewProxy.getInstance().setKeyboard(); 6805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6820e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka /** 6830e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * Enables or disables the key feedback popup. This is a popup that shows a magnified 6840e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * version of the depressed key. By default the preview is enabled. 6850e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @param previewEnabled whether or not to enable the key feedback preview 6860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @param delay the delay after which the preview is dismissed 6870e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @see #isKeyPreviewPopupEnabled() 6880e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka */ 6890e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) { 6900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mShowKeyPreviewPopup = previewEnabled; 6910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewLingerTimeout = delay; 6920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 6930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 694375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 695375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void locatePreviewPlacerView() { 696375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mPreviewPlacerView.getParent() != null) { 697375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 698375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 699375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int width = getWidth(); 700375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int height = getHeight(); 701375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (width == 0 || height == 0) { 702375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In transient state. 703375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 704375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 705375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka getLocationInWindow(mOriginCoords); 706375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final DisplayMetrics dm = getResources().getDisplayMetrics(); 707375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (CoordinateUtils.y(mOriginCoords) < dm.heightPixels / 4) { 708375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In transient state. 709375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 710375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 711375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final View rootView = getRootView(); 712375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (rootView == null) { 713375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka Log.w(TAG, "Cannot find root view"); 714375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 715375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 716375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content); 717375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Note: It'd be very weird if we get null by android.R.id.content. 718375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (windowContentView == null) { 719375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka Log.w(TAG, "Cannot find android.R.id.content view to add PreviewPlacerView"); 720375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 721375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka windowContentView.addView(mPreviewPlacerView); 722375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height); 723375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 724375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 725375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 7260e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka /** 7270e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * Returns the enabled state of the key feedback preview 7280e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @return whether or not the key feedback preview is enabled 7290e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @see #setKeyPreviewPopupEnabled(boolean, int) 7300e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka */ 7310e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public boolean isKeyPreviewPopupEnabled() { 7320e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return mShowKeyPreviewPopup; 7330e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7340e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 735375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void addKeyPreview(final TextView keyPreview) { 736375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 737375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.addView( 738375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacerView, 0, 0)); 739375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 740375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 741375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private TextView getKeyPreviewText(final int pointerId) { 742375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka TextView previewText = mKeyPreviewTexts.get(pointerId); 743375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 744375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return previewText; 745375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 746375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final Context context = getContext(); 747375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mKeyPreviewLayoutId != 0) { 748375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText = (TextView)LayoutInflater.from(context).inflate(mKeyPreviewLayoutId, null); 749375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 750375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText = new TextView(context); 751375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 752375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyPreviewTexts.put(pointerId, previewText); 753375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return previewText; 754375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 755375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 756375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void dismissAllKeyPreviews() { 757375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int pointerCount = mKeyPreviewTexts.size(); 758375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka for (int id = 0; id < pointerCount; id++) { 759375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final TextView previewText = mKeyPreviewTexts.get(id); 760375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (previewText != null) { 761375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka previewText.setVisibility(INVISIBLE); 762375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 763375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 764375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka PointerTracker.setReleasedKeyGraphicsToAllKeys(); 765375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 766375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 7670e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Background state set 7680e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { 7690e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_MIDDLE 7700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka EMPTY_STATE_SET, 7710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_has_morekeys } 7720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }, 7730e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_LEFT 7740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_left_edge }, 7750e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_left_edge, R.attr.state_has_morekeys } 7760e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }, 7770e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_RIGHT 7780e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_right_edge }, 7790e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_right_edge, R.attr.state_has_morekeys } 7800e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7810e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }; 7820e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_MIDDLE = 0; 7830e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_LEFT = 1; 7840e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_RIGHT = 2; 7850e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_NORMAL = 0; 7860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_HAS_MOREKEYS = 1; 7870e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int[] KEY_PREVIEW_BACKGROUND_DEFAULT_STATE = 7880e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka KEY_PREVIEW_BACKGROUND_STATE_TABLE[STATE_MIDDLE][STATE_NORMAL]; 7890e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 7910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void showKeyPreview(final PointerTracker tracker) { 7920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams; 7930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 7940e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (!mShowKeyPreviewPopup) { 7950e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleOffset = -keyboard.mVerticalGap; 7960e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return; 7970e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final TextView previewText = getKeyPreviewText(tracker.mPointerId); 8000e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // If the key preview has no parent view yet, add it to the ViewGroup which can place 8010e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // key preview absolutely in SoftInputWindow. 8020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (previewText.getParent() == null) { 8030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka addKeyPreview(previewText); 8040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8050e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8060e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mDrawingHandler.cancelDismissKeyPreview(tracker); 8070e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Key key = tracker.getKey(); 8080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // If key is invalid or IME is already closed, we must not show key preview. 8090e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Trying to show key preview while root window is closed causes 8100e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // WindowManager.BadTokenException. 8110e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (key == null) { 8120e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return; 8130e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8140e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8150e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final KeyDrawParams drawParams = mKeyDrawParams; 8160e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setTextColor(drawParams.mPreviewTextColor); 8170e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final Drawable background = previewText.getBackground(); 8180e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (background != null) { 8190e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka background.setState(KEY_PREVIEW_BACKGROUND_DEFAULT_STATE); 8200e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka background.setAlpha(PREVIEW_ALPHA); 8210e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 822914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka final String label = key.getPreviewLabel(); 8230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // What we show as preview should match what we show on a key top in onDraw(). 8240e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (label != null) { 8250e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // TODO Should take care of temporaryShiftLabel here. 8260e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setCompoundDrawables(null, null, null, null); 827914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, 828914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka key.selectPreviewTextSize(drawParams)); 829914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka previewText.setTypeface(key.selectPreviewTypeface(drawParams)); 8300e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setText(label); 8310e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 8320e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setCompoundDrawables(null, null, null, 8330e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka key.getPreviewIcon(keyboard.mIconsSet)); 8340e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setText(null); 8350e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8360e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8370e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.measure( 8380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 8390e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int keyDrawWidth = key.getDrawWidth(); 8400e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewWidth = previewText.getMeasuredWidth(); 8410e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewHeight = mKeyPreviewHeight; 8420e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The width and height of visible part of the key preview background. The content marker 8430e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // of the background 9-patch have to cover the visible part of the background. 8440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleWidth = previewWidth - previewText.getPaddingLeft() 8450e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka - previewText.getPaddingRight(); 8460e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleHeight = previewHeight - previewText.getPaddingTop() 8470e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka - previewText.getPaddingBottom(); 8480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The distance between the top edge of the parent key and the bottom of the visible part 8490e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // of the key preview background. 8500e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewParams.mPreviewVisibleOffset = mKeyPreviewOffset - previewText.getPaddingBottom(); 8510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka getLocationInWindow(mOriginCoords); 8520e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The key preview is horizontally aligned with the center of the visible part of the 8530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and 8540e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // the left/right background is used if such background is specified. 8550e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int statePosition; 8560e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 8570e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka + CoordinateUtils.x(mOriginCoords); 8580e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (previewX < 0) { 8590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewX = 0; 8600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_LEFT; 8610e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else if (previewX > getWidth() - previewWidth) { 8620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewX = getWidth() - previewWidth; 8630e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_RIGHT; 8640e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 8650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_MIDDLE; 8660e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8670e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The key preview is placed vertically above the top edge of the parent key with an 8680e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // arbitrary offset. 8690e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewY = key.mY - previewHeight + mKeyPreviewOffset 8700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka + CoordinateUtils.y(mOriginCoords); 8710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (background != null) { 8730e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int hasMoreKeys = (key.mMoreKeys != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; 8740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); 8750e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8760e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka ViewLayoutUtils.placeViewAt( 8770e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText, previewX, previewY, previewWidth, previewHeight); 8780e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 8790e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8800e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8810e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8820e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void dismissKeyPreview(final PointerTracker tracker) { 8830e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, tracker); 8840e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8850e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 886ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka public void setSlidingKeyInputPreviewEnabled(final boolean enabled) { 887ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mSlidingKeyInputPreview.setPreviewEnabled(enabled); 888ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka } 889ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka 8900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void showSlidingKeyInputPreview(final PointerTracker tracker) { 8920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka locatePreviewPlacerView(); 893fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview.setPreviewPosition(tracker); 8940e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 8950e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 8960e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 8970e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void dismissSlidingKeyInputPreview() { 898fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview.dismissSlidingKeyInputPreview(); 8990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 9000e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 901375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void setGesturePreviewMode(final boolean drawsGesturePreviewTrail, 902375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final boolean drawsGestureFloatingPreviewText) { 903fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText.setPreviewEnabled(drawsGestureFloatingPreviewText); 904fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview.setPreviewEnabled(drawsGesturePreviewTrail); 905375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 906375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 907375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) { 908375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 909fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText.setSuggetedWords(suggestedWords); 910375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 911375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 912375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissGestureFloatingPreviewText() { 913375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 914375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mDrawingHandler.dismissGestureFloatingPreviewText(mGestureFloatingPreviewTextLingerTimeout); 915375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 916375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 917fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka @Override 918ab334eb64669e909f0a401fddffa891962002602Tadashi G. Takaoka public void showGesturePreviewTrail(final PointerTracker tracker) { 919375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 920fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText.setPreviewPosition(tracker); 921fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview.setPreviewPosition(tracker); 922375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 923375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 9248335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 925dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 9268335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable); 9278335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 9288335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 929dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setGestureHandlingEnabledByUser(final boolean gestureHandlingEnabledByUser) { 9308335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setGestureHandlingEnabledByUser(gestureHandlingEnabledByUser); 9310657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka } 9320657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka 9335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 9344331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge protected void onAttachedToWindow() { 9354331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge super.onAttachedToWindow(); 9369c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Notify the ResearchLogger (development only diagnostics) that the keyboard view has 9379c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // been attached. This is needed to properly show the splash screen, which requires that 9389c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // the window token of the KeyboardView be non-null. 9399c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 940c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow(this); 941c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 942c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 943c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka 944c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka @Override 945c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka protected void onDetachedFromWindow() { 946c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka super.onDetachedFromWindow(); 947375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.removeAllViews(); 9489c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Notify the ResearchLogger (development only diagnostics) that the keyboard view has 9499c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // been detached. This is needed to invalidate the reference of {@link MainKeyboardView} 9509c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // to null. 9519c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 952c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onDetachedFromWindow(); 9534331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 9544331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 9554331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge 956a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) { 957a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (key.mMoreKeys == null) { 9585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return null; 95920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 960a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key); 961a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (moreKeysKeyboard == null) { 962a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka moreKeysKeyboard = new MoreKeysKeyboard.Builder( 963a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka context, key, this, mKeyPreviewDrawParams).build(); 964a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.put(key, moreKeysKeyboard); 96520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 9665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 967a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final View container = mMoreKeysKeyboardContainer; 9682affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka final MoreKeysKeyboardView moreKeysKeyboardView = 9692affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); 9702affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); 971b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 9722affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka return moreKeysKeyboardView; 9735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 9755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 976d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * Called when a key is long pressed. 9775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param tracker the pointer tracker which pressed the parent key 9785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return true if the long press is handled, false otherwise. Subclasses should call the 9795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * method on the base class if the subclass doesn't wish to handle the call. 9805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 981a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private boolean onLongPress(final PointerTracker tracker) { 982a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 983a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return false; 984a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 985a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final Key key = tracker.getKey(); 986a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (key == null) { 987a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return false; 988a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 9899c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 990c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_onLongPress(); 9919bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 992a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int code = key.mCode; 993a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (key.hasEmbeddedMoreKey()) { 994a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int embeddedCode = key.mMoreKeys[0].mCode; 9953708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka tracker.onLongPressed(); 996e491be6e8690ffb8359887838fa12d5873346be5Tadashi G. Takaoka invokeCodeInput(embeddedCode); 997a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka invokeReleaseKey(code); 998a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka KeyboardSwitcher.getInstance().hapticAndAudioFeedback(code); 9993708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka return true; 10003708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka } 1001a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) { 10023708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka // Long pressing the space key invokes IME switcher dialog. 10033708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { 10046dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 1005a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka invokeReleaseKey(code); 100642e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka return true; 10076dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 10086dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 1009a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return openMoreKeysPanel(key, tracker); 10106dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 10116dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 1012a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private boolean invokeCustomRequest(final int requestCode) { 1013a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return mKeyboardActionListener.onCustomRequest(requestCode); 101442e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka } 101542e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka 1016a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private void invokeCodeInput(final int code) { 1017ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka mKeyboardActionListener.onCodeInput( 1018a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 101942e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka } 102042e8c64a042476f555da5015558d51f96aaeb7fdTadashi G. Takaoka 1021a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private void invokeReleaseKey(final int code) { 1022a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mKeyboardActionListener.onReleaseKey(code, false); 10236dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 10246dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 1025a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private boolean openMoreKeysPanel(final Key key, final PointerTracker tracker) { 1026a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = onCreateMoreKeysPanel(key, getContext()); 10279d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (moreKeysPanel == null) { 1028a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return false; 10295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 103063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 1031547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 1032547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.getLastCoordinates(lastCoords); 1033a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !key.noKeyPreview(); 10347ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually horizontally aligned with the center of the parent key. 10357ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more 10367ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // keys keyboard is placed at the touch point of the parent key. 10377ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled) 1038547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka ? CoordinateUtils.x(lastCoords) 1039a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka : key.mX + key.mWidth / 2; 10407ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually vertically aligned with the top edge of the parent key 10417ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically 10427ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // aligned with the bottom edge of the visible part of the key preview. 104329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@code mPreviewVisibleOffset} has been set appropriately in 104429d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@link KeyboardView#showKeyPreview(PointerTracker)}. 1045a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int pointY = key.mY + mKeyPreviewDrawParams.mPreviewVisibleOffset; 1046fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); 1047547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(CoordinateUtils.x(lastCoords)); 1048547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(CoordinateUtils.y(lastCoords)); 1049e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaoka tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); 10505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 10515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 1054a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 105563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return true; 10565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 105720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return PointerTracker.isAnyInSlidingKeyInput(); 10585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1060d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 1061d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public void onShowMoreKeysPanel(final MoreKeysPanel panel) { 10621b6eea89037158a1e271730eacdacb8b6e550d3aTadashi G. Takaoka locatePreviewPlacerView(); 1063d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 1064d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka onDismissMoreKeysPanel(); 1065d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1066a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mPreviewPlacerView.addView(panel.getContainerView()); 1067d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMoreKeysPanel = panel; 1068a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka dimEntireKeyboard(true /* dimmed */); 1069d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1070d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 1071d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public boolean isShowingMoreKeysPanel() { 1072a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return mMoreKeysPanel != null && mMoreKeysPanel.isShowingInParent(); 1073d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1074d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 1075d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 1076d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public void onCancelMoreKeysPanel() { 1077d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka PointerTracker.dismissAllMoreKeysPanels(); 1078d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1079d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 1080d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 1081d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public boolean onDismissMoreKeysPanel() { 1082d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka dimEntireKeyboard(false /* dimmed */); 1083d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 1084d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mPreviewPlacerView.removeView(mMoreKeysPanel.getContainerView()); 1085d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMoreKeysPanel = null; 1086d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka return true; 1087d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1088d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka return false; 1089d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 1090d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 10915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public int getPointerCount() { 10925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mOldPointerCount; 10935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 1096dc2ee7772402633817702e95c2a5b17f6dec03ebalanv public boolean dispatchTouchEvent(MotionEvent event) { 1097dc2ee7772402633817702e95c2a5b17f6dec03ebalanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 1098dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return AccessibleKeyboardViewProxy.getInstance().dispatchTouchEvent(event); 1099dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 1100dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return super.dispatchTouchEvent(event); 1101dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 1102dc2ee7772402633817702e95c2a5b17f6dec03ebalanv 1103dc2ee7772402633817702e95c2a5b17f6dec03ebalanv @Override 1104dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean onTouchEvent(final MotionEvent me) { 110546286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka if (getKeyboard() == null) { 110646286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka return false; 110746286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka } 1108c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka return mTouchScreenRegulator.onTouchEvent(me); 1109c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 1110c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 1111c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka @Override 1112dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean processMotionEvent(final MotionEvent me) { 1113f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final boolean nonDistinctMultitouch = !mHasDistinctMultitouch; 11145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int action = me.getActionMasked(); 11155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int pointerCount = me.getPointerCount(); 11165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int oldPointerCount = mOldPointerCount; 11175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mOldPointerCount = pointerCount; 11185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 11205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // If the device does not have distinct multi-touch support panel, ignore all multi-touch 11215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // events except a transition from/to single-touch. 1122f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) { 11235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 11245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final long eventTime = me.getEventTime(); 11275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int index = me.getActionIndex(); 11285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int id = me.getPointerId(index); 112935580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int x = (int)me.getX(index); 113035580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int y = (int)me.getY(index); 113135580bad6f3da3b204653825bbb6871563e70728Tom Ouyang 1132fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // TODO: This might be moved to the tracker.processMotionEvent() call below. 1133fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka if (ENABLE_USABILITY_STUDY_LOG && action != MotionEvent.ACTION_MOVE) { 1134fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka writeUsabilityStudyLog(me, action, eventTime, index, id, x, y); 1135d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 1136fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // TODO: This should be moved to the tracker.processMotionEvent() call below. 1137fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // Currently the same "move" event is being logged twice. 11389c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 1139fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka ResearchLogger.mainKeyboardView_processMotionEvent( 1140fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka me, action, eventTime, index, id, x, y); 114115d4793911fa305e0a58aced925961e948582979satok } 11425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1143f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (mKeyTimerHandler.isInKeyRepeat()) { 1144e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 11455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Key repeating timer will be canceled if 2 or more keys are in action, and current 11465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // event (UP or DOWN) is non-modifier key. 11475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount > 1 && !tracker.isModifier()) { 1148f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelKeyRepeatTimer(); 11495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Up event will pass through. 11515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 11545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Translate mutli-touch event to single-touch events on the device that has no distinct 11555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // multi-touch panel. 1156f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch) { 11575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Use only main (id=0) pointer tracker. 1158e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 11595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount == 1 && oldPointerCount == 2) { 11605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Multi-touch to single touch transition. 11615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send a down event for the latest pointer if the key is different from the 11625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // previous key. 1163e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka final Key newKey = tracker.getKeyOn(x, y); 1164e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka if (mOldKey != newKey) { 11650efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka tracker.onDownEvent(x, y, eventTime, this); 1166fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka if (action == MotionEvent.ACTION_UP) { 1167906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka tracker.onUpEvent(x, y, eventTime); 1168fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 11695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 2 && oldPointerCount == 1) { 11715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Single-touch to multi-touch transition. 11725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send an up event for the last pointer. 1173547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 1174547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka mOldKey = tracker.getKeyOn( 1175547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords)); 1176547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.onUpEvent( 1177547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime); 11785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 1 && oldPointerCount == 1) { 11798ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 11805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 11815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount 11825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka + " (old " + oldPointerCount + ")"); 11835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 11855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 11865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 11875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (action == MotionEvent.ACTION_MOVE) { 11885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka for (int i = 0; i < pointerCount; i++) { 1189d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge final int pointerId = me.getPointerId(i); 1190e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker( 1191d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge pointerId, this); 119235580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int px = (int)me.getX(i); 119335580bad6f3da3b204653825bbb6871563e70728Tom Ouyang final int py = (int)me.getY(i); 119435580bad6f3da3b204653825bbb6871563e70728Tom Ouyang tracker.onMoveEvent(px, py, eventTime, me); 1195d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge if (ENABLE_USABILITY_STUDY_LOG) { 1196fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka writeUsabilityStudyLog(me, action, eventTime, i, pointerId, px, py); 1197d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 11981bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // TODO: This seems to be no longer necessary, and confusing because it leads to 11991bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // duplicate MotionEvents being recorded. 12001bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 12011bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // ResearchLogger.mainKeyboardView_processMotionEvent( 12021bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // me, action, eventTime, i, pointerId, px, py); 12031bf47582a050a682154ea2bb3822219e41e4258eKurt Partridge // } 12045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 12055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 1206e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 1207e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka tracker.processMotionEvent(action, x, y, eventTime, this); 12085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 12095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 12105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 12115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 12125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1213fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka private static void writeUsabilityStudyLog(final MotionEvent me, final int action, 1214fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final long eventTime, final int index, final int id, final int x, final int y) { 1215fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final String eventTag; 1216fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka switch (action) { 1217fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_UP: 1218fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Up]"; 1219fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1220fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_DOWN: 1221fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Down]"; 1222fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1223fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 1224fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[PointerUp]"; 1225fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1226fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 1227fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[PointerDown]"; 1228fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1229fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka case MotionEvent.ACTION_MOVE: 1230fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Move]"; 1231fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1232fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka default: 1233fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag = "[Action" + action + "]"; 1234fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka break; 1235fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 1236fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final float size = me.getSize(index); 1237fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka final float pressure = me.getPressure(index); 1238fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka UsabilityStudyLogUtils.getInstance().write( 1239fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka eventTag + eventTime + "," + id + "," + x + "," + y + "," + size + "," + pressure); 1240fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka } 1241fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka 1242375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void cancelAllMessages() { 1243375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyTimerHandler.cancelAllMessages(); 1244375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mDrawingHandler.cancelAllMessages(); 1245375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 1246375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 12475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void closing() { 1248375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka dismissAllKeyPreviews(); 1249375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka cancelAllMessages(); 1250a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka onDismissMoreKeysPanel(); 1251a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.clear(); 12525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 12535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1254586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette /** 1255c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka * Receives hover events from the input framework. 1256586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * 1257586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @param event The motion event to be dispatched. 1258586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @return {@code true} if the event was handled by the view, {@code false} 1259586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * otherwise 1260586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette */ 1261c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka @Override 1262dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean dispatchHoverEvent(final MotionEvent event) { 12635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 1264e88e1b22c87a075554fb3f10cee492e169570958Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, this); 1265586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker); 12665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 12675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1268586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette // Reflection doesn't support calling superclass methods. 12695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 12705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 127122b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 1272dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateShortcutKey(final boolean available) { 12737bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 127420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (keyboard == null) { 127520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 127620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1277240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT); 127820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (shortcutKey == null) { 127920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 128020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 12817bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka shortcutKey.setEnabled(available); 12827bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka invalidateKey(shortcutKey); 12835afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka } 12845afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka 128573a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka private void updateAltCodeKeyWhileTyping() { 128673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 128720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (keyboard == null) { 128820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 128920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 129073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka for (final Key key : keyboard.mAltCodeKeysWhileTyping) { 129173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka invalidateKey(key); 129273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 129373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 129473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 1295dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, 1296dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final boolean needsToDisplayLanguage, final boolean hasMultipleEnabledIMEsOrSubtypes) { 12974112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mNeedsToDisplayLanguage = needsToDisplayLanguage; 1298fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; 1299fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; 1300d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator == null) { 1301aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka mNeedsToDisplayLanguage = false; 13024c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } else { 1303dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka if (subtypeChanged && needsToDisplayLanguage) { 13044daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); 130531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (animator.isStarted()) { 130631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.cancel(); 130731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 1308d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka animator.start(); 1309dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } else { 131031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (!animator.isStarted()) { 131131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha; 131231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 1313dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } 13144c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } 13154112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 13164112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13174112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1318dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateAutoCorrectionState(final boolean isAutoCorrection) { 131920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (!mAutoCorrectionSpacebarLedEnabled) { 132020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 132120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 13224112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedOn = isAutoCorrection; 13234112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 132422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 132522b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 1326a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private void dimEntireKeyboard(final boolean dimmed) { 1327f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka final boolean needsRedrawing = mNeedsToDimEntireKeyboard != dimmed; 1328f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mNeedsToDimEntireKeyboard = dimmed; 1329f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka if (needsRedrawing) { 1330f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka invalidateAllKeys(); 1331f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1332f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1333f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 1334f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka @Override 1335f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka protected void onDraw(final Canvas canvas) { 1336f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka super.onDraw(canvas); 1337f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 1338f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka // Overlay a dark rectangle to dim. 1339f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka if (mNeedsToDimEntireKeyboard) { 134008ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mBackgroundDimAlphaPaint); 1341f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1342f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1343f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 134422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka @Override 1345dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, 1346dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final KeyDrawParams params) { 13476bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.altCodeWhileTyping() && key.isEnabled()) { 134873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha; 134973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 1350240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (key.mCode == Constants.CODE_SPACE) { 1351bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawSpacebar(key, canvas, paint); 13524112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Whether space key needs to show the "..." popup hint for special purposes 1353fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) { 1354bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 13554112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 1356240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka } else if (key.mCode == Constants.CODE_LANGUAGE_SWITCH) { 135781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 1358fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 1359b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka } else { 1360b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 136122b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 136222b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 13634112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 136408ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka private static boolean fitsTextIntoWidth(final int width, final String text, 136508ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final Paint paint) { 1366bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(1.0f); 136708ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final float textWidth = TypefaceUtils.getLabelWidth(text, paint); 136820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (textWidth < width) { 136920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return true; 137020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1371bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1372bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final float scaleX = width / textWidth; 137320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) { 137420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return false; 137520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1376bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1377bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(scaleX); 137808ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka return TypefaceUtils.getLabelWidth(text, paint) < width; 1379bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 1380bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1381bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Layout language name on spacebar. 138208ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka private static String layoutLanguageOnSpacebar(final Paint paint, 138308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final InputMethodSubtype subtype, final int width) { 1384bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Choose appropriate language name to fit into the width. 13854b3cae9b0cbd5bf30a1c8da383ff247f9c2afc5aTadashi G. Takaoka final String fullText = getFullDisplayName(subtype); 138620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, fullText, paint)) { 138720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return fullText; 1388bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 1389bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 139020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka final String middleText = getMiddleDisplayName(subtype); 139120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, middleText, paint)) { 139220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return middleText; 13934112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13944112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 139520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka final String shortText = getShortDisplayName(subtype); 139620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, shortText, paint)) { 139720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return shortText; 13984112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 13994112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1400bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return ""; 14014112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 14024112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1403dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void drawSpacebar(final Key key, final Canvas canvas, final Paint paint) { 1404bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka final int width = key.mWidth; 1405b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final int height = key.mHeight; 14064112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1407f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka // If input language are explicitly selected. 1408bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mNeedsToDisplayLanguage) { 1409bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextAlign(Align.CENTER); 1410bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTypeface(Typeface.DEFAULT); 1411bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextSize(mSpacebarTextSize); 1412bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final InputMethodSubtype subtype = getKeyboard().mId.mSubtype; 1413bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final String language = layoutLanguageOnSpacebar(paint, subtype, width); 14144112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw language text with shadow 14154112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float descent = paint.descent(); 14164112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float textHeight = -paint.ascent() + descent; 1417b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final float baseline = height / 2 + textHeight / 2; 1418aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextShadowColor); 141931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 14204112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent - 1, paint); 1421aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka paint.setColor(mSpacebarTextColor); 142231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 14234112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent, paint); 14244112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 14254112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 14264112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw the spacebar icon at the bottom 1427bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mAutoCorrectionSpacebarLedOn) { 14284112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; 14294112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); 14304112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 14314112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1432bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight); 14334112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } else if (mSpaceIcon != null) { 14344112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = mSpaceIcon.getIntrinsicWidth(); 14354112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mSpaceIcon.getIntrinsicHeight(); 14364112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 14374112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1438bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight); 14394112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 14404112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 144127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 144227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // InputMethodSubtype's display name for spacebar text in its locale. 144327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // isAdditionalSubtype (T=true, F=false) 144476d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // locale layout | Short Middle Full 144576d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // ------ ------- - ---- --------- ---------------------- 144676d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // en_US qwerty F En English English (US) exception 144776d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // en_GB qwerty F En English English (UK) exception 144876d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // es_US spanish F Es Español Español (EE.UU.) exception 144976d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // fr azerty F Fr Français Français 145076d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // fr_CA qwerty F Fr Français Français (Canada) 145176d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // de qwertz F De Deutsch Deutsch 145276d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // zz qwerty F QWERTY QWERTY 14538630cd9d1708d42b3ed5d07d89ade2f3c1f85e47Tadashi G. Takaoka // fr qwertz T Fr Français Français 14548630cd9d1708d42b3ed5d07d89ade2f3c1f85e47Tadashi G. Takaoka // de qwerty T De Deutsch Deutsch 14558630cd9d1708d42b3ed5d07d89ade2f3c1f85e47Tadashi G. Takaoka // en_US azerty T En English English (US) 145676d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka // zz azerty T AZERTY AZERTY 145727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 145827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's full display name in its locale. 14594b3cae9b0cbd5bf30a1c8da383ff247f9c2afc5aTadashi G. Takaoka static String getFullDisplayName(final InputMethodSubtype subtype) { 146027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 146127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype); 146227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 14638630cd9d1708d42b3ed5d07d89ade2f3c1f85e47Tadashi G. Takaoka return SubtypeLocale.getSubtypeLocaleDisplayName(subtype.getLocale()); 146427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 146527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 146627b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's short display name in its locale. 1467dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka static String getShortDisplayName(final InputMethodSubtype subtype) { 146827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 146927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return ""; 147027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 147127b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka final Locale locale = SubtypeLocale.getSubtypeLocale(subtype); 147299b93d17d53c2d587c45373831b327f7851ec0a8Jean Chalard return StringUtils.capitalizeFirstCodePoint(locale.getLanguage(), locale); 147327b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 147427b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka 147527b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka // Get InputMethodSubtype's middle display name in its locale. 1476dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka static String getMiddleDisplayName(final InputMethodSubtype subtype) { 147727b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka if (SubtypeLocale.isNoLanguage(subtype)) { 147827b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka return SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype); 147927b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 148027b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka final Locale locale = SubtypeLocale.getSubtypeLocale(subtype); 14818630cd9d1708d42b3ed5d07d89ade2f3c1f85e47Tadashi G. Takaoka return SubtypeLocale.getSubtypeLocaleDisplayName(locale.getLanguage()); 148227b42ced86e1c85de3d59d91a9e5c577fa552569Tadashi G. Takaoka } 14835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka} 1484