MainKeyboardView.java revision 6a23b9e3d54031524445b1190cc1eba77916c5b3
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 192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport android.animation.Animator; 20d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaokaimport android.animation.AnimatorInflater; 212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport android.animation.AnimatorListenerAdapter; 222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport android.animation.AnimatorSet; 2331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaokaimport android.animation.ObjectAnimator; 245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.Context; 2513ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport android.content.SharedPreferences; 265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.pm.PackageManager; 274112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.content.res.TypedArray; 286dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport android.graphics.Canvas; 29f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaokaimport android.graphics.Color; 3022b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaokaimport android.graphics.Paint; 314112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.Paint.Align; 32bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaokaimport android.graphics.Typeface; 334112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.drawable.Drawable; 3413ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport android.preference.PreferenceManager; 355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.AttributeSet; 36375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport android.util.DisplayMetrics; 375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.Log; 380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport android.util.TypedValue; 395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.LayoutInflater; 405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.MotionEvent; 415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.View; 42b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaokaimport android.view.ViewGroup; 432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport android.view.animation.AccelerateInterpolator; 442fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport android.view.animation.DecelerateInterpolator; 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; 512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport com.android.inputmethod.keyboard.internal.DrawingHandler; 52fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureFloatingPreviewText; 53fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureTrailsPreview; 5449d8af8a4e900f3c68c333aba7fde0a11fd368b1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyDrawParams; 550e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; 56b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper; 57375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PreviewPlacerView; 58fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.SlidingKeyInputPreview; 592fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport com.android.inputmethod.keyboard.internal.TimerHandler; 604daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport com.android.inputmethod.latin.Constants; 6115d4793911fa305e0a58aced925961e948582979satokimport com.android.inputmethod.latin.LatinImeLogger; 625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 63375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords; 64c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 65a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.DebugSettings; 66e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils; 67e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CoordinateUtils; 68a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaokaimport com.android.inputmethod.latin.utils.SubtypeLocaleUtils; 69ccf4a310279b13bbf0b6aac76a0878178c1dfb7dTadashi G. Takaokaimport com.android.inputmethod.latin.utils.TypefaceUtils; 704be6198cb73cc24e10834153c4e049644ed187e3Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.UsabilityStudyLogUtils; 71ccf4a310279b13bbf0b6aac76a0878178c1dfb7dTadashi G. Takaokaimport com.android.inputmethod.latin.utils.ViewLayoutUtils; 726b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport java.util.ArrayDeque; 752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport java.util.HashMap; 762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport java.util.HashSet; 775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap; 785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/** 805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements. 815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 82dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedEnabled 83dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedIcon 842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextRatio 852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextColor 862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowColor 872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_spacebarBackground 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 952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_keySelectionByDraggingFinger 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 */ 1212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasapublic final class MainKeyboardView extends KeyboardView implements PointerTracker.DrawingProxy, 1222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa MoreKeysPanel.Controller, DrawingHandler.Callbacks, TimerHandler.Callbacks { 123c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka private static final String TAG = MainKeyboardView.class.getSimpleName(); 1245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 125bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka /** Listener for {@link KeyboardActionListener}. */ 126bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private KeyboardActionListener mKeyboardActionListener; 127bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka 1282fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa /* Space key and its icon and background. */ 1294112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka private Key mSpaceKey; 1302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private Drawable mSpacebarIcon; 1312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final Drawable mSpacebarBackground; 132bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw language name on spacebar. 13331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private final int mLanguageOnSpacebarFinalAlpha; 13431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; 135bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mNeedsToDisplayLanguage; 136fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka private boolean mHasMultipleEnabledIMEsOrSubtypes; 1374daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE; 1382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final float mLanguageOnSpacebarTextRatio; 1392fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private float mLanguageOnSpacebarTextSize; 1402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final int mLanguageOnSpacebarTextColor; 1412fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final int mLanguageOnSpacebarTextShadowColor; 142bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // The minimum x-scale to fit the language name on spacebar. 143bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f; 144bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka // Stuff to draw auto correction LED on spacebar. 145bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private boolean mAutoCorrectionSpacebarLedOn; 146bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final boolean mAutoCorrectionSpacebarLedEnabled; 147bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private final Drawable mAutoCorrectionSpacebarLedIcon; 148bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka private static final int SPACE_LED_LENGTH_PERCENT = 80; 14915d4793911fa305e0a58aced925961e948582979satok 15073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka // Stuff to draw altCodeWhileTyping keys. 1512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator; 1522fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator; 1534daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE; 15473a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 155375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Preview placer view 156375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final PreviewPlacerView mPreviewPlacerView; 157375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final int[] mOriginCoords = CoordinateUtils.newInstance(); 158fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final GestureFloatingPreviewText mGestureFloatingPreviewText; 159fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final GestureTrailsPreview mGestureTrailsPreview; 160fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka private final SlidingKeyInputPreview mSlidingKeyInputPreview; 161375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 1620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Key preview 1632fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static final boolean FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED = false; 164375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private final int mKeyPreviewLayoutId; 1650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final int mKeyPreviewOffset; 1660e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final int mKeyPreviewHeight; 1672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Free {@link TextView} pool that can be used for key preview. 1682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final ArrayDeque<TextView> mFreeKeyPreviewTextViews = CollectionUtils.newArrayDeque(); 1692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Map from {@link Key} to {@link TextView} that is currently being displayed as key preview. 1702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final HashMap<Key,TextView> mShowingKeyPreviewTextViews = CollectionUtils.newHashMap(); 1710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private final KeyPreviewDrawParams mKeyPreviewDrawParams = new KeyPreviewDrawParams(); 1720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private boolean mShowKeyPreviewPopup = true; 1730e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private int mKeyPreviewLingerTimeout; 1742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private int mKeyPreviewZoomInDuration; 1752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private int mKeyPreviewZoomOutDuration; 1762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static final float KEY_PREVIEW_START_ZOOM_IN_SCALE = 0.7f; 1772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static final float KEY_PREVIEW_END_ZOOM_IN_SCALE = 1.0f; 1782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static final float KEY_PREVIEW_END_ZOOM_OUT_SCALE = 0.7f; 1792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = 1802fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa new AccelerateInterpolator(); 1812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = 1822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa new DecelerateInterpolator(); 1830e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 1842affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka // More keys keyboard 185f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka private final Paint mBackgroundDimAlphaPaint = new Paint(); 186f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka private boolean mNeedsToDimEntireKeyboard; 187a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private final View mMoreKeysKeyboardContainer; 188a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = 189a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka CollectionUtils.newWeakHashMap(); 1902affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint; 191d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka // More keys panel (used by both more keys keyboard and more suggestions view) 192d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka // TODO: Consider extending to support multiple more keys panels 193d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka private MoreKeysPanel mMoreKeysPanel; 1945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 195375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Gesture floating preview text 196375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // TODO: Make this parameter customizable by user via settings. 197375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private int mGestureFloatingPreviewTextLingerTimeout; 198375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 1992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final KeyDetector mKeyDetector; 200b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka private final NonDistinctMultitouchHelper mNonDistinctMultitouchHelper; 2015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2022fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final TimerHandler mKeyTimerHandler; 203741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka private final int mLanguageOnSpacebarHorizontalMargin; 2045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final DrawingHandler mDrawingHandler = 2062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa new DrawingHandler(this); 207375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 208dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs) { 209c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka this(context, attrs, R.attr.mainKeyboardViewStyle); 2105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 212dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) { 2135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(context, attrs, defStyle); 2145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mPreviewPlacerView = new PreviewPlacerView(context, attrs); 2162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 2172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes( 2182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView); 2192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int ignoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt( 2202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0); 2212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int gestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt( 2222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0); 2232fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyTimerHandler = new TimerHandler( 2242fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa this, ignoreAltCodeKeyTimeout, gestureRecognitionUpdateTime); 2252fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 2262fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension( 2272fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f); 2282fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension( 2292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f); 2302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyDetector = new KeyDetector( 2312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier); 2322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 2332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa PointerTracker.init(mainKeyboardViewAttr, mKeyTimerHandler, this /* DrawingProxy */, 2342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyDetector); 2352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 23613ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 23713ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean forceNonDistinctMultitouch = prefs.getBoolean( 238a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false); 23913ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka final boolean hasDistinctMultitouch = context.getPackageManager() 240b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT) 241b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka && !forceNonDistinctMultitouch; 242b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka mNonDistinctMultitouchHelper = hasDistinctMultitouch ? null 2432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa : new NonDistinctMultitouchHelper(PointerTracker.getPointerTracker(0)); 24422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 245f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka final int backgroundDimAlpha = mainKeyboardViewAttr.getInt( 246f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka R.styleable.MainKeyboardView_backgroundDimAlpha, 0); 247f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mBackgroundDimAlphaPaint.setColor(Color.BLACK); 248f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha); 2492fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mSpacebarBackground = mainKeyboardViewAttr.getDrawable( 2502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_spacebarBackground); 251d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mAutoCorrectionSpacebarLedEnabled = mainKeyboardViewAttr.getBoolean( 252c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false); 253d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mAutoCorrectionSpacebarLedIcon = mainKeyboardViewAttr.getDrawable( 254c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_autoCorrectionSpacebarLedIcon); 2552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mLanguageOnSpacebarTextRatio = mainKeyboardViewAttr.getFraction( 2562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f); 2572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mLanguageOnSpacebarTextColor = mainKeyboardViewAttr.getColor( 2582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_languageOnSpacebarTextColor, 0); 2592fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mLanguageOnSpacebarTextShadowColor = mainKeyboardViewAttr.getColor( 2602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_languageOnSpacebarTextShadowColor, 0); 261d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt( 262c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha, 2634daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang Constants.Color.ALPHA_OPAQUE); 264d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int languageOnSpacebarFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId( 265c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0); 266d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId( 267c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0); 268d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka final int altCodeKeyWhileTypingFadeinAnimatorResId = mainKeyboardViewAttr.getResourceId( 269c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0); 270160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 2710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewOffset = mainKeyboardViewAttr.getDimensionPixelOffset( 2720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewOffset, 0); 2730e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewHeight = mainKeyboardViewAttr.getDimensionPixelSize( 2740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewHeight, 0); 2750e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewLingerTimeout = mainKeyboardViewAttr.getInt( 2760e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0); 277375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyPreviewLayoutId = mainKeyboardViewAttr.getResourceId( 278375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka R.styleable.MainKeyboardView_keyPreviewLayout, 0); 2790e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (mKeyPreviewLayoutId == 0) { 2800e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mShowKeyPreviewPopup = false; 2810e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 2822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyPreviewZoomInDuration = mainKeyboardViewAttr.getInt( 2832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_keyPreviewZoomInDuration, 0); 2842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyPreviewZoomOutDuration = mainKeyboardViewAttr.getInt( 2852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.styleable.MainKeyboardView_keyPreviewZoomOutDuration, 0); 286a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId( 287d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0); 288d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean( 289c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false); 290375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 291375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mGestureFloatingPreviewTextLingerTimeout = mainKeyboardViewAttr.getInt( 292375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0); 293fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 294fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText = new GestureFloatingPreviewText( 295fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 296fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mGestureFloatingPreviewText); 297fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 298fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview = new GestureTrailsPreview( 299fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 300fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mGestureTrailsPreview); 301fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 302fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview = new SlidingKeyInputPreview( 303fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView, mainKeyboardViewAttr); 304fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mPreviewPlacerView.addPreview(mSlidingKeyInputPreview); 305d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mainKeyboardViewAttr.recycle(); 306160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka 307a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardContainer = LayoutInflater.from(getContext()) 308a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka .inflate(moreKeysKeyboardLayoutId, null); 30931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator( 31031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka languageOnSpacebarFadeoutAnimatorResId, this); 31131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator( 31231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeoutAnimatorResId, this); 31331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator( 31431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka altCodeKeyWhileTypingFadeinAnimatorResId, this); 315f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka 316f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; 317741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka 3182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mLanguageOnSpacebarHorizontalMargin = (int)getResources().getDimension( 3192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.dimen.config_language_on_spacebar_horizontal_margin); 32031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 32131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 32252876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa @Override 32352876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) { 32452876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa super.setHardwareAcceleratedDrawingEnabled(enabled); 32552876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa mPreviewPlacerView.setHardwareAcceleratedDrawingEnabled(enabled); 32652876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa } 32752876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa 328dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private ObjectAnimator loadObjectAnimator(final int resId, final Object target) { 32920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (resId == 0) { 33057372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka // TODO: Stop returning null. 33120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return null; 33220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 33331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator( 33431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka getContext(), resId); 335d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator != null) { 33631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.setTarget(target); 33773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 33831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return animator; 33931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 34073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 3412fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, 3422fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final ObjectAnimator animatorToStart) { 3432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (animatorToCancel == null || animatorToStart == null) { 3442fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Stop using null as a no-operation animator. 3452fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 3462fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 3472fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa float startFraction = 0.0f; 3482fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (animatorToCancel.isStarted()) { 3492fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa animatorToCancel.cancel(); 3502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa startFraction = 1.0f - animatorToCancel.getAnimatedFraction(); 3512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 3522fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final long startTime = (long)(animatorToStart.getDuration() * startFraction); 3532fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa animatorToStart.start(); 3542fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa animatorToStart.setCurrentPlayTime(startTime); 3552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 3562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 3572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Implements {@link TimerHander.Callbacks} method. 3582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 3592fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void startWhileTypingFadeinAnimation() { 3602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa cancelAndStartAnimators( 3612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mAltCodeKeyWhileTypingFadeoutAnimator, mAltCodeKeyWhileTypingFadeinAnimator); 3622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 3632fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 3642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 3652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void startWhileTypingFadeoutAnimation() { 3662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa cancelAndStartAnimators( 3672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mAltCodeKeyWhileTypingFadeinAnimator, mAltCodeKeyWhileTypingFadeoutAnimator); 3682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 3692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 37015f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 37131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getLanguageOnSpacebarAnimAlpha() { 37231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mLanguageOnSpacebarAnimAlpha; 373d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka } 374d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka 37515f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 376dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setLanguageOnSpacebarAnimAlpha(final int alpha) { 37731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = alpha; 37831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka invalidateKey(mSpaceKey); 37931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 38031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 38115f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 38231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka public int getAltCodeKeyWhileTypingAnimAlpha() { 38331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return mAltCodeKeyWhileTypingAnimAlpha; 38431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 38531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 38615f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @ExternallyReferenced 387dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) { 3885141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka if (mAltCodeKeyWhileTypingAnimAlpha == alpha) { 3895141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka return; 3905141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 3915141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka // Update the visual of alt-code-key-while-typing. 39231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mAltCodeKeyWhileTypingAnimAlpha = alpha; 3935141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 3945141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka if (keyboard == null) { 3955141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka return; 3965141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 3975141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka for (final Key key : keyboard.mAltCodeKeysWhileTyping) { 3985141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka invalidateKey(key); 3995141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka } 4005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 402dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboardActionListener(final KeyboardActionListener listener) { 4035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyboardActionListener = listener; 4045c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.setKeyboardActionListener(listener); 4055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4065f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: We should reconsider which coordinate system should be used to represent keyboard 4082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // event. 4092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public int getKeyX(final int x) { 4102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return Constants.isValidCoordinate(x) ? mKeyDetector.getTouchX(x) : x; 4115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: We should reconsider which coordinate system should be used to represent keyboard 4142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // event. 4152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public int getKeyY(final int y) { 4162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return Constants.isValidCoordinate(y) ? mKeyDetector.getTouchY(y) : y; 4170efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 4180efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 4195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 4205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Attaches a keyboard to this view. The keyboard can be switched at any time and the 4215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * view will re-layout itself to accommodate the keyboard. 4225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see Keyboard 4235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see #getKeyboard() 4245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param keyboard the keyboard to display in this view 4255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 4265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 427dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setKeyboard(final Keyboard keyboard) { 4282fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Remove any pending messages. 4292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyTimerHandler.cancelAllKeyTimers(); 4305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.setKeyboard(keyboard); 4315a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyDetector.setKeyboard( 43208ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection()); 4338335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setKeyDetector(mKeyDetector); 4342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa PointerTracker.setKeyboardActionListener(mKeyboardActionListener); 435a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.clear(); 4364112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 437240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka mSpaceKey = keyboard.getKey(Constants.CODE_SPACE); 4382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mSpacebarIcon = (mSpaceKey != null) 4394daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang ? mSpaceKey.getIcon(keyboard.mIconsSet, Constants.Color.ALPHA_OPAQUE) : null; 4404112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; 4412fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mLanguageOnSpacebarTextSize = keyHeight * mLanguageOnSpacebarTextRatio; 4429c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 44315c42454c0117d869f31ce278021f53ec74c4aa2Tadashi G. Takaoka final int orientation = getContext().getResources().getConfiguration().orientation; 44415c42454c0117d869f31ce278021f53ec74c4aa2Tadashi G. Takaoka ResearchLogger.mainKeyboardView_setKeyboard(keyboard, orientation); 44548a7681e064ae259b840f0e757da2d716043d893Kurt Partridge } 446f147794fd41491a3383e6aca6d49007f58124068alanv 447f147794fd41491a3383e6aca6d49007f58124068alanv // This always needs to be set since the accessibility state can 448f147794fd41491a3383e6aca6d49007f58124068alanv // potentially change without the keyboard being set again. 449b6ca354431367b625daf9fff5fbe4b1f5ef996abKen Wakasa AccessibleKeyboardViewProxy.getInstance().setKeyboard(); 4505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4520e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka /** 4530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * Enables or disables the key feedback popup. This is a popup that shows a magnified 4540e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * version of the depressed key. By default the preview is enabled. 4550e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @param previewEnabled whether or not to enable the key feedback preview 4560e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @param delay the delay after which the preview is dismissed 4570e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @see #isKeyPreviewPopupEnabled() 4580e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka */ 4590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) { 4600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mShowKeyPreviewPopup = previewEnabled; 4610e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka mKeyPreviewLingerTimeout = delay; 4620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 4630e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 464375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka private void locatePreviewPlacerView() { 465375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mPreviewPlacerView.getParent() != null) { 466375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 467375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 468375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int width = getWidth(); 469375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final int height = getHeight(); 470375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (width == 0 || height == 0) { 471375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In transient state. 472375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 473375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 474375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka getLocationInWindow(mOriginCoords); 475375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final DisplayMetrics dm = getResources().getDisplayMetrics(); 476375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (CoordinateUtils.y(mOriginCoords) < dm.heightPixels / 4) { 477375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In transient state. 478375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 479375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 480375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final View rootView = getRootView(); 481375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (rootView == null) { 482375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka Log.w(TAG, "Cannot find root view"); 483375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return; 484375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 485375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content); 486375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // Note: It'd be very weird if we get null by android.R.id.content. 487375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (windowContentView == null) { 488375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka Log.w(TAG, "Cannot find android.R.id.content view to add PreviewPlacerView"); 489375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 490375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka windowContentView.addView(mPreviewPlacerView); 491375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, width, height); 492375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 493375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 494375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 4950e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka /** 4960e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * Returns the enabled state of the key feedback preview 4970e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @return whether or not the key feedback preview is enabled 4980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @see #setKeyPreviewPopupEnabled(boolean, int) 4990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka */ 5000e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public boolean isKeyPreviewPopupEnabled() { 5010e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return mShowKeyPreviewPopup; 5020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 5030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 5042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private TextView getKeyPreviewTextView(final Key key) { 5052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); 5062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (previewTextView != null) { 5072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return previewTextView; 5082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 5092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView = mFreeKeyPreviewTextViews.poll(); 5102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (previewTextView != null) { 5112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return previewTextView; 512375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 513375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final Context context = getContext(); 514375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (mKeyPreviewLayoutId != 0) { 5152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView = (TextView)LayoutInflater.from(context) 5162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa .inflate(mKeyPreviewLayoutId, null); 517375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 5182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView = new TextView(context); 519375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 5202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa locatePreviewPlacerView(); 5212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mPreviewPlacerView.addView( 5222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView, ViewLayoutUtils.newLayoutParam(mPreviewPlacerView, 0, 0)); 5232fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return previewTextView; 524375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 525375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 5262fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Implements {@link DrawingHandler.Callbacks} method. 5272fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 5282fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void dismissAllKeyPreviews() { 5292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa for (final Key key : new HashSet<Key>(mShowingKeyPreviewTextViews.keySet())) { 5302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa dismissKeyPreviewWithoutDelay(key); 531375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 532375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka PointerTracker.setReleasedKeyGraphicsToAllKeys(); 533375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 534375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 5350e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Background state set 5360e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int[][][] KEY_PREVIEW_BACKGROUND_STATE_TABLE = { 5370e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_MIDDLE 5380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka EMPTY_STATE_SET, 5390e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_has_morekeys } 5400e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }, 5410e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_LEFT 5420e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_left_edge }, 5430e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_left_edge, R.attr.state_has_morekeys } 5440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }, 5450e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { // STATE_RIGHT 5460e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_right_edge }, 5470e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka { R.attr.state_right_edge, R.attr.state_has_morekeys } 5480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 5490e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }; 5500e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_MIDDLE = 0; 5510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_LEFT = 1; 5520e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_RIGHT = 2; 5530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_NORMAL = 0; 5540e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka private static final int STATE_HAS_MOREKEYS = 1; 5550e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 5562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Take this method out of this class. 5570e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 5582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void showKeyPreview(final Key key) { 5590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // If key is invalid or IME is already closed, we must not show key preview. 5600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // Trying to show key preview while root window is closed causes 5610e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // WindowManager.BadTokenException. 5620e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (key == null) { 5630e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return; 5640e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 5650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 5662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams; 5672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final Keyboard keyboard = getKeyboard(); 5682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (!mShowKeyPreviewPopup) { 5692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewParams.mPreviewVisibleOffset = -keyboard.mVerticalGap; 5702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 5712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 5722fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 5732fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final TextView previewTextView = getKeyPreviewTextView(key); 5740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final KeyDrawParams drawParams = mKeyDrawParams; 5752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setTextColor(drawParams.mPreviewTextColor); 5762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final Drawable background = previewTextView.getBackground(); 577914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka final String label = key.getPreviewLabel(); 5780e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // What we show as preview should match what we show on a key top in onDraw(). 5790e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (label != null) { 5800e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // TODO Should take care of temporaryShiftLabel here. 5812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setCompoundDrawables(null, null, null, null); 5822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 583914d054ea26d18a1ba6a60f8c5e749136477bbf2Tadashi G. Takaoka key.selectPreviewTextSize(drawParams)); 5842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setTypeface(key.selectPreviewTypeface(drawParams)); 5852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setText(label); 5860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 5872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setCompoundDrawables(null, null, null, 5880e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka key.getPreviewIcon(keyboard.mIconsSet)); 5892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setText(null); 5900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 5910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 5922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.measure( 5930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 5940e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int keyDrawWidth = key.getDrawWidth(); 5952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int previewWidth = previewTextView.getMeasuredWidth(); 5960e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int previewHeight = mKeyPreviewHeight; 5970e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The width and height of visible part of the key preview background. The content marker 5980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // of the background 9-patch have to cover the visible part of the background. 5992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewParams.mPreviewVisibleWidth = previewWidth - previewTextView.getPaddingLeft() 6002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa - previewTextView.getPaddingRight(); 6012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewParams.mPreviewVisibleHeight = previewHeight - previewTextView.getPaddingTop() 6022fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa - previewTextView.getPaddingBottom(); 6030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The distance between the top edge of the parent key and the bottom of the visible part 6040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // of the key preview background. 6052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewParams.mPreviewVisibleOffset = 6062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyPreviewOffset - previewTextView.getPaddingBottom(); 6070e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka getLocationInWindow(mOriginCoords); 6080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The key preview is horizontally aligned with the center of the visible part of the 6090e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // parent key. If it doesn't fit in this {@link KeyboardView}, it is moved inward to fit and 6100e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // the left/right background is used if such background is specified. 6110e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka final int statePosition; 6120e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2 6130e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka + CoordinateUtils.x(mOriginCoords); 6140e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (previewX < 0) { 6150e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewX = 0; 6160e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_LEFT; 6170e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else if (previewX > getWidth() - previewWidth) { 6180e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka previewX = getWidth() - previewWidth; 6190e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_RIGHT; 6200e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 6210e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka statePosition = STATE_MIDDLE; 6220e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 6230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // The key preview is placed vertically above the top edge of the parent key with an 6240e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka // arbitrary offset. 6257dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int previewY = key.getY() - previewHeight + mKeyPreviewOffset 6260e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka + CoordinateUtils.y(mOriginCoords); 6270e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 6280e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (background != null) { 6297dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int hasMoreKeys = (key.getMoreKeys() != null) ? STATE_HAS_MOREKEYS : STATE_NORMAL; 6300e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka background.setState(KEY_PREVIEW_BACKGROUND_STATE_TABLE[statePosition][hasMoreKeys]); 6310e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 6320e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka ViewLayoutUtils.placeViewAt( 6332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView, previewX, previewY, previewWidth, previewHeight); 6342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 6352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (!isHardwareAccelerated()) { 6362fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setVisibility(VISIBLE); 6372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mShowingKeyPreviewTextViews.put(key, previewTextView); 6382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 6392fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setPivotX(previewWidth / 2.0f); 6412fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setPivotY(previewHeight); 6422fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 6432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final Animator zoomIn = createZoomInAniation(key, previewTextView); 6442fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final Animator zoomOut = createZoomOutAnimation(key, previewTextView); 6452fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final KeyPreviewAnimations animation = new KeyPreviewAnimations(zoomIn, zoomOut); 6462fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setTag(animation); 6472fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa animation.startZoomIn(); 6480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 6490e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 6502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Move this internal class out to a separate external class. 6512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private static class KeyPreviewAnimations extends AnimatorListenerAdapter { 6522fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final Animator mZoomIn; 6532fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final Animator mZoomOut; 6542fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 6552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public KeyPreviewAnimations(final Animator zoomIn, final Animator zoomOut) { 6562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mZoomIn = zoomIn; 6572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mZoomOut = zoomOut; 6582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6592fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 6602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void startZoomIn() { 6612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mZoomIn.start(); 6622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6632fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 6642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void startZoomOut() { 6652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (mZoomIn.isRunning()) { 6662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mZoomIn.addListener(this); 6672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 6682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mZoomOut.start(); 6702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 6722fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 6732fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void onAnimationEnd(final Animator animation) { 6742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mZoomOut.start(); 6752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 6782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Take this method out of this class. 6792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private Animator createZoomInAniation(final Key key, final TextView previewTextView) { 6802fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( 6812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView, SCALE_X, KEY_PREVIEW_START_ZOOM_IN_SCALE, 6822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa KEY_PREVIEW_END_ZOOM_IN_SCALE); 6832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( 6842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView, SCALE_Y, KEY_PREVIEW_START_ZOOM_IN_SCALE, 6852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa KEY_PREVIEW_END_ZOOM_IN_SCALE); 6862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final AnimatorSet zoomInAnimation = new AnimatorSet(); 6872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa zoomInAnimation.play(scaleXAnimation).with(scaleYAnimation); 6882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Implement preference option to control key preview animation duration. 6892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa zoomInAnimation.setDuration(mKeyPreviewZoomInDuration); 6902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa zoomInAnimation.setInterpolator(DECELERATE_INTERPOLATOR); 6912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa zoomInAnimation.addListener(new AnimatorListenerAdapter() { 6922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 6932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void onAnimationStart(final Animator animation) { 6942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setVisibility(VISIBLE); 6952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mShowingKeyPreviewTextViews.put(key, previewTextView); 6962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa }); 6982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return zoomInAnimation; 6992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 7012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Take this method out of this class. 7022fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private Animator createZoomOutAnimation(final Key key, final TextView previewTextView) { 7032fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat( 7042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView, SCALE_X, KEY_PREVIEW_END_ZOOM_OUT_SCALE); 7052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat( 7062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView, SCALE_Y, KEY_PREVIEW_END_ZOOM_OUT_SCALE); 7072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final AnimatorSet zoomOutAnimation = new AnimatorSet(); 7082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa zoomOutAnimation.play(scaleXAnimation).with(scaleYAnimation); 7092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Implement preference option to control key preview animation duration. 7102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa zoomOutAnimation.setDuration(mKeyPreviewZoomOutDuration); 7112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa zoomOutAnimation.setInterpolator(ACCELERATE_INTERPOLATOR); 7122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa zoomOutAnimation.addListener(new AnimatorListenerAdapter() { 7132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 7142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void onAnimationEnd(final Animator animation) { 7152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa dismissKeyPreviewWithoutDelay(key); 7162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa }); 7182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return zoomOutAnimation; 7192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 7212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Implements {@link TimerHandler.Callbacks} method. 7222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Take this method out of this class. 7230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 7242fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void dismissKeyPreviewWithoutDelay(final Key key) { 7252fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (key == null) { 7262fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 7272fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7282fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final TextView previewTextView = mShowingKeyPreviewTextViews.remove(key); 7292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (previewTextView != null) { 7302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final Object tag = previewTextView.getTag(); 7312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (tag instanceof Animator) { 7322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa ((Animator)tag).cancel(); 7332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setTag(null); 7352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa previewTextView.setVisibility(INVISIBLE); 7362fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mFreeKeyPreviewTextViews.add(previewTextView); 7372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // To redraw key top letter. 7392fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa invalidateKey(key); 7402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7412fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 7422fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Take this method out of this class. 7432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 7442fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void dismissKeyPreview(final Key key) { 7452fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final TextView previewTextView = mShowingKeyPreviewTextViews.get(key); 7462fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (previewTextView == null) { 7472fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 7482fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7492fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (!isHardwareAccelerated()) { 7502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Implement preference option to control key preview method and duration. 7512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mDrawingHandler.dismissKeyPreview(mKeyPreviewLingerTimeout, key); 7522fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 7532fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7542fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final Object tag = previewTextView.getTag(); 7552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (tag instanceof KeyPreviewAnimations) { 7562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag; 7572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa animation.startZoomOut(); 7582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 761ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka public void setSlidingKeyInputPreviewEnabled(final boolean enabled) { 762ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mSlidingKeyInputPreview.setPreviewEnabled(enabled); 763ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka } 764ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka 7650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 7660e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void showSlidingKeyInputPreview(final PointerTracker tracker) { 7670e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka locatePreviewPlacerView(); 768fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview.setPreviewPosition(tracker); 7690e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 7710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka @Override 7720e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka public void dismissSlidingKeyInputPreview() { 773fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mSlidingKeyInputPreview.dismissSlidingKeyInputPreview(); 7740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 7750e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 776724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa private void setGesturePreviewMode(final boolean isGestureTrailEnabled, 777724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa final boolean isGestureFloatingPreviewTextEnabled) { 778724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa mGestureFloatingPreviewText.setPreviewEnabled(isGestureFloatingPreviewTextEnabled); 779724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa mGestureTrailsPreview.setPreviewEnabled(isGestureTrailEnabled); 780375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 781375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 7822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Implements {@link DrawingHandler.Callbacks} method. 7832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 784375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) { 785375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 786fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureFloatingPreviewText.setSuggetedWords(suggestedWords); 787375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 788375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 789375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka public void dismissGestureFloatingPreviewText() { 790375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 791375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mDrawingHandler.dismissGestureFloatingPreviewText(mGestureFloatingPreviewTextLingerTimeout); 792375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 793375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 794fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka @Override 795212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka public void showGestureTrail(final PointerTracker tracker, 796212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka final boolean showsFloatingPreviewText) { 797375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka locatePreviewPlacerView(); 798212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka if (showsFloatingPreviewText) { 799212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka mGestureFloatingPreviewText.setPreviewPosition(tracker); 800212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka } 801fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka mGestureTrailsPreview.setPreviewPosition(tracker); 802375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 803375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 8048335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 805dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { 8068335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable); 8078335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 8088335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 809724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa public void setGestureHandlingEnabledByUser(final boolean isGestureHandlingEnabledByUser, 810724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa final boolean isGestureTrailEnabled, 811724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa final boolean isGestureFloatingPreviewTextEnabled) { 812724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa PointerTracker.setGestureHandlingEnabledByUser(isGestureHandlingEnabledByUser); 813724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa setGesturePreviewMode(isGestureHandlingEnabledByUser && isGestureTrailEnabled, 814724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa isGestureHandlingEnabledByUser && isGestureFloatingPreviewTextEnabled); 8150657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka } 8160657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka 8175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 8184331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge protected void onAttachedToWindow() { 8194331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge super.onAttachedToWindow(); 8209c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Notify the ResearchLogger (development only diagnostics) that the keyboard view has 8219c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // been attached. This is needed to properly show the splash screen, which requires that 8229c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // the window token of the KeyboardView be non-null. 8239c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 824c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onAttachedToWindow(this); 825c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 826c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka } 827c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka 828c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka @Override 829c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka protected void onDetachedFromWindow() { 830c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka super.onDetachedFromWindow(); 831375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mPreviewPlacerView.removeAllViews(); 8329c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Notify the ResearchLogger (development only diagnostics) that the keyboard view has 8339c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // been detached. This is needed to invalidate the reference of {@link MainKeyboardView} 8349c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // to null. 8359c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 836c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka ResearchLogger.getInstance().mainKeyboardView_onDetachedFromWindow(); 8374331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 8384331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge } 8394331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge 840a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) { 8417dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka if (key.getMoreKeys() == null) { 8425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return null; 84320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 844a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key); 845a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (moreKeysKeyboard == null) { 846a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka moreKeysKeyboard = new MoreKeysKeyboard.Builder( 847a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka context, key, this, mKeyPreviewDrawParams).build(); 848a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.put(key, moreKeysKeyboard); 84920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 8505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 851a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final View container = mMoreKeysKeyboardContainer; 8522affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka final MoreKeysKeyboardView moreKeysKeyboardView = 8532affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view); 8542affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka moreKeysKeyboardView.setKeyboard(moreKeysKeyboard); 855b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 8562affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka return moreKeysKeyboardView; 8575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 8585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 8592fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Implements {@link TimerHandler.Callbacks} method. 8605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 861d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * Called when a key is long pressed. 8625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param tracker the pointer tracker which pressed the parent key 8635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 8642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 8652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void onLongPress(final PointerTracker tracker) { 866a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 86796efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 868a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 869a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final Key key = tracker.getKey(); 870a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (key == null) { 87196efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 872a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 8739c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 874c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka ResearchLogger.mainKeyboardView_onLongPress(); 8759bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 876f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka final KeyboardActionListener listener = mKeyboardActionListener; 8779552badf3c24d2098d227b0ddca0721b928a10b1Tadashi G. Takaoka if (key.hasNoPanelAutoMoreKey()) { 8787dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int moreKeyCode = key.getMoreKeys()[0].mCode; 8793708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka tracker.onLongPressed(); 880ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka listener.onPressKey(moreKeyCode, 0 /* repeatCount */, true /* isSinglePointer */); 881f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onCodeInput(moreKeyCode, 882f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 883f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onReleaseKey(moreKeyCode, false /* withSliding */); 88496efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 8853708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka } 8867dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int code = key.getCode(); 887a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) { 8883708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka // Long pressing the space key invokes IME switcher dialog. 889f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka if (listener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) { 8906dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 891f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka listener.onReleaseKey(code, false /* withSliding */); 89296efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 8936dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 8946dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 89596efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka openMoreKeysPanel(key, tracker); 8966dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 8976dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 89896efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka private void openMoreKeysPanel(final Key key, final PointerTracker tracker) { 899a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = onCreateMoreKeysPanel(key, getContext()); 9009d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (moreKeysPanel == null) { 90196efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka return; 9025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 90363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 904547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka final int[] lastCoords = CoordinateUtils.newInstance(); 905547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka tracker.getLastCoordinates(lastCoords); 906a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka final boolean keyPreviewEnabled = isKeyPreviewPopupEnabled() && !key.noKeyPreview(); 9077ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually horizontally aligned with the center of the parent key. 9087ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more 9097ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // keys keyboard is placed at the touch point of the parent key. 9107ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled) 911547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka ? CoordinateUtils.x(lastCoords) 9127dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka : key.getX() + key.getWidth() / 2; 9137ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // The more keys keyboard is usually vertically aligned with the top edge of the parent key 9147ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically 9157ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka // aligned with the bottom edge of the visible part of the key preview. 91629d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@code mPreviewVisibleOffset} has been set appropriately in 91729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka // {@link KeyboardView#showKeyPreview(PointerTracker)}. 9187dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int pointY = key.getY() + mKeyPreviewDrawParams.mPreviewVisibleOffset; 919fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener); 92033482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka tracker.onShowMoreKeysPanel(moreKeysPanel); 9212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Implement zoom in animation of more keys panel. 9222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa dismissKeyPreviewWithoutDelay(key); 9235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 9252fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public boolean isInDraggingFinger() { 926a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 92763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return true; 9285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return PointerTracker.isAnyInDraggingFinger(); 9305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 9315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 932d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 933d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public void onShowMoreKeysPanel(final MoreKeysPanel panel) { 9341b6eea89037158a1e271730eacdacb8b6e550d3aTadashi G. Takaoka locatePreviewPlacerView(); 9357f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka panel.showInParent(mPreviewPlacerView); 936d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMoreKeysPanel = panel; 937a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka dimEntireKeyboard(true /* dimmed */); 938d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 939d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 940d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka public boolean isShowingMoreKeysPanel() { 941a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka return mMoreKeysPanel != null && mMoreKeysPanel.isShowingInParent(); 942d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 943d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 944d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 9450e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { 946d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka PointerTracker.dismissAllMoreKeysPanels(); 947d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 948d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 949d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka @Override 9500e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { 951d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka dimEntireKeyboard(false /* dimmed */); 952d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka if (isShowingMoreKeysPanel()) { 9537f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka mMoreKeysPanel.removeFromParent(); 954d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMoreKeysPanel = null; 955d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 956d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 957d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 9585433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka public void startDoubleTapShiftKeyTimer() { 9595433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka mKeyTimerHandler.startDoubleTapShiftKeyTimer(); 9605433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka } 9615433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 9625433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka public void cancelDoubleTapShiftKeyTimer() { 9635433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka mKeyTimerHandler.cancelDoubleTapShiftKeyTimer(); 9645433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka } 9655433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 9665433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka public boolean isInDoubleTapShiftKeyTimeout() { 9675433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka return mKeyTimerHandler.isInDoubleTapShiftKeyTimeout(); 9685433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka } 9695433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 9705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 971dc2ee7772402633817702e95c2a5b17f6dec03ebalanv public boolean dispatchTouchEvent(MotionEvent event) { 972dc2ee7772402633817702e95c2a5b17f6dec03ebalanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 973dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return AccessibleKeyboardViewProxy.getInstance().dispatchTouchEvent(event); 974dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 975dc2ee7772402633817702e95c2a5b17f6dec03ebalanv return super.dispatchTouchEvent(event); 976dc2ee7772402633817702e95c2a5b17f6dec03ebalanv } 977dc2ee7772402633817702e95c2a5b17f6dec03ebalanv 978dc2ee7772402633817702e95c2a5b17f6dec03ebalanv @Override 979dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean onTouchEvent(final MotionEvent me) { 98046286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka if (getKeyboard() == null) { 98146286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka return false; 98246286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka } 983b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka if (mNonDistinctMultitouchHelper != null) { 984b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka if (me.getPointerCount() > 1 && mKeyTimerHandler.isInKeyRepeat()) { 985b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka // Key repeating timer will be canceled if 2 or more keys are in action. 9862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mKeyTimerHandler.cancelKeyRepeatTimers(); 987b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka } 988b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka // Non distinct multitouch screen support 9892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mNonDistinctMultitouchHelper.processMotionEvent(me, mKeyDetector); 990b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka return true; 991b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka } 992310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka return processMotionEvent(me); 993c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka } 994c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 995dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean processMotionEvent(final MotionEvent me) { 99630977a151e15e30f5385a349e92fb770b987435fTadashi G. Takaoka if (LatinImeLogger.sUsabilityStudy) { 99730977a151e15e30f5385a349e92fb770b987435fTadashi G. Takaoka UsabilityStudyLogUtils.writeMotionEvent(me); 998d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge } 999fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka // Currently the same "move" event is being logged twice. 10009c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 100154dd1bed528331208f15df2693bcd01004dd471aTadashi G. Takaoka ResearchLogger.mainKeyboardView_processMotionEvent(me); 100215d4793911fa305e0a58aced925961e948582979satok } 10035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1004e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int index = me.getActionIndex(); 1005e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka final int id = me.getPointerId(index); 10062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final PointerTracker tracker = PointerTracker.getPointerTracker(id); 10072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // When a more keys panel is showing, we should ignore other fingers' single touch events 10082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // other than the finger that is showing the more keys panel. 10092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (isShowingMoreKeysPanel() && !tracker.isShowingMoreKeysPanel() 10102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa && PointerTracker.getActivePointerTrackerCount() == 1) { 10112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return true; 10122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 10132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa tracker.processMotionEvent(me, mKeyDetector); 10145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 10155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 10175c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka public void cancelAllOngoingEvents() { 1018375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mKeyTimerHandler.cancelAllMessages(); 1019375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka mDrawingHandler.cancelAllMessages(); 10205c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissAllKeyPreviews(); 10215c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissGestureFloatingPreviewText(); 10225c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka dismissSlidingKeyInputPreview(); 10235c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka PointerTracker.dismissAllMoreKeysPanels(); 10245c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka PointerTracker.cancelAllPointerTrackers(); 1025375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 1026375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 10275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void closing() { 10285c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka cancelAllOngoingEvents(); 1029a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka mMoreKeysKeyboardCache.clear(); 10305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1032586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette /** 1033c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka * Receives hover events from the input framework. 1034586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * 1035586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @param event The motion event to be dispatched. 1036586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @return {@code true} if the event was handled by the view, {@code false} 1037586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * otherwise 1038586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette */ 1039c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka @Override 1040dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public boolean dispatchHoverEvent(final MotionEvent event) { 10415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 10426a23b9e3d54031524445b1190cc1eba77916c5b3Tadashi G. Takaoka return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent( 10436a23b9e3d54031524445b1190cc1eba77916c5b3Tadashi G. Takaoka event, mKeyDetector); 10445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 10455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1046586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette // Reflection doesn't support calling superclass methods. 10475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 10485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 104922b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 1050dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateShortcutKey(final boolean available) { 10517bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 105220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (keyboard == null) { 105320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 105420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1055240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT); 105620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (shortcutKey == null) { 105720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 105820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 10597bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka shortcutKey.setEnabled(available); 10607bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka invalidateKey(shortcutKey); 10615afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka } 10625afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka 1063dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, 1064dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final boolean needsToDisplayLanguage, final boolean hasMultipleEnabledIMEsOrSubtypes) { 10654112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mNeedsToDisplayLanguage = needsToDisplayLanguage; 1066fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; 1067fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; 1068d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (animator == null) { 1069aee5f03d6ebf9cb03b52cbea003556f38745b4feTadashi G. Takaoka mNeedsToDisplayLanguage = false; 10704c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } else { 1071dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka if (subtypeChanged && needsToDisplayLanguage) { 10724daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE); 107331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (animator.isStarted()) { 107431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka animator.cancel(); 107531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 1076d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka animator.start(); 1077dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } else { 107831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (!animator.isStarted()) { 107931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha; 108031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 1081dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka } 10824c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } 10834112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 10844112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 10854112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1086dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka public void updateAutoCorrectionState(final boolean isAutoCorrection) { 108720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (!mAutoCorrectionSpacebarLedEnabled) { 108820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return; 108920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 10904112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka mAutoCorrectionSpacebarLedOn = isAutoCorrection; 10914112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka invalidateKey(mSpaceKey); 109222b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 109322b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka 1094a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka private void dimEntireKeyboard(final boolean dimmed) { 1095f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka final boolean needsRedrawing = mNeedsToDimEntireKeyboard != dimmed; 1096f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka mNeedsToDimEntireKeyboard = dimmed; 1097f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka if (needsRedrawing) { 1098f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka invalidateAllKeys(); 1099f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1100f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1101f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 1102f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka @Override 1103f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka protected void onDraw(final Canvas canvas) { 1104f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka super.onDraw(canvas); 1105f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 1106f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka // Overlay a dark rectangle to dim. 1107f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka if (mNeedsToDimEntireKeyboard) { 110808ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mBackgroundDimAlphaPaint); 1109f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1110f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 1111f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 11122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Draw key background. 11132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 11142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa protected void onDrawKeyBackground(final Key key, final Canvas canvas, 11152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final Drawable background) { 11162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (key.getCode() == Constants.CODE_SPACE) { 11172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa super.onDrawKeyBackground(key, canvas, mSpacebarBackground); 11182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 11192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 11202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa super.onDrawKeyBackground(key, canvas, background); 11212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 11222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 112322b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka @Override 1124dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, 1125dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka final KeyDrawParams params) { 11266bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka if (key.altCodeWhileTyping() && key.isEnabled()) { 112773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha; 112873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 11292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Don't draw key top letter when key preview is showing. 11302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED 11312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa && mShowingKeyPreviewTextViews.containsKey(key)) { 11322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // TODO: Fade out animation for the key top letter, and fade in animation for the key 11332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // background color when the user presses the key. 11342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return; 11352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 11367dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int code = key.getCode(); 11377dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka if (code == Constants.CODE_SPACE) { 1138bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawSpacebar(key, canvas, paint); 11394112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Whether space key needs to show the "..." popup hint for special purposes 1140fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) { 1141bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 11424112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 11437dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka } else if (code == Constants.CODE_LANGUAGE_SWITCH) { 114481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 1145fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka drawKeyPopupHint(key, canvas, paint, params); 1146b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka } else { 1147b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka super.onDrawKeyTopVisuals(key, canvas, paint, params); 114822b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 114922b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka } 11504112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1151741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka private boolean fitsTextIntoWidth(final int width, final String text, final Paint paint) { 1152741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka final int maxTextWidth = width - mLanguageOnSpacebarHorizontalMargin * 2; 1153bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(1.0f); 11542fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final float textWidth = TypefaceUtils.getStringWidth(text, paint); 115520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (textWidth < width) { 115620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return true; 115720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1158bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1159741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka final float scaleX = maxTextWidth / textWidth; 116020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) { 116120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return false; 116220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 1163bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1164bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextScaleX(scaleX); 11652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return TypefaceUtils.getStringWidth(text, paint) < maxTextWidth; 1166bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 1167bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1168bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Layout language name on spacebar. 1169741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka private String layoutLanguageOnSpacebar(final Paint paint, 117008ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka final InputMethodSubtype subtype, final int width) { 1171741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka 1172bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka // Choose appropriate language name to fit into the width. 1173a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String fullText = SubtypeLocaleUtils.getFullDisplayName(subtype); 117420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, fullText, paint)) { 117520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return fullText; 1176bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 1177bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka 1178a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String middleText = SubtypeLocaleUtils.getMiddleDisplayName(subtype); 117920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, middleText, paint)) { 118020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return middleText; 11814112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 11824112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1183a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String shortText = SubtypeLocaleUtils.getShortDisplayName(subtype); 118420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (fitsTextIntoWidth(width, shortText, paint)) { 118520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return shortText; 11864112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 11874112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1188bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return ""; 11894112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 11904112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1191dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka private void drawSpacebar(final Key key, final Canvas canvas, final Paint paint) { 11927dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int width = key.getWidth(); 11937dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int height = key.getHeight(); 11944112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 1195f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka // If input language are explicitly selected. 1196bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mNeedsToDisplayLanguage) { 1197bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTextAlign(Align.CENTER); 1198bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka paint.setTypeface(Typeface.DEFAULT); 11992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa paint.setTextSize(mLanguageOnSpacebarTextSize); 1200bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final InputMethodSubtype subtype = getKeyboard().mId.mSubtype; 1201bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka final String language = layoutLanguageOnSpacebar(paint, subtype, width); 12024112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw language text with shadow 12034112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float descent = paint.descent(); 12044112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final float textHeight = -paint.ascent() + descent; 1205b19a6b9fc55910bd241bee3b312169a818cb721dTadashi G. Takaoka final float baseline = height / 2 + textHeight / 2; 12062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa paint.setColor(mLanguageOnSpacebarTextShadowColor); 120731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 12084112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent - 1, paint); 12092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa paint.setColor(mLanguageOnSpacebarTextColor); 121031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka paint.setAlpha(mLanguageOnSpacebarAnimAlpha); 12114112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka canvas.drawText(language, width / 2, baseline - descent, paint); 12124112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 12134112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 12144112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // Draw the spacebar icon at the bottom 1215bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka if (mAutoCorrectionSpacebarLedOn) { 12164112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; 12174112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); 12184112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 12194112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 1220bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight); 12212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } else if (mSpacebarIcon != null) { 12222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int iconWidth = mSpacebarIcon.getIntrinsicWidth(); 12232fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final int iconHeight = mSpacebarIcon.getIntrinsicHeight(); 12244112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int x = (width - iconWidth) / 2; 12254112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int y = height - iconHeight; 12262fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa drawIcon(canvas, mSpacebarIcon, x, y, iconWidth, iconHeight); 12274112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 12284112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 1229c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa 1230e68d565d0f9704145adbf781105f1ac9a90f0a98Ken Wakasa @Override 1231c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa public void deallocateMemory() { 1232e68d565d0f9704145adbf781105f1ac9a90f0a98Ken Wakasa super.deallocateMemory(); 1233c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa mGestureTrailsPreview.deallocateMemory(); 1234c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa } 12355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka} 1236