15f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/*
25f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project
35f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka *
45f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
55f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * you may not use this file except in compliance with the License.
65f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * You may obtain a copy of the License at
75f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka *
85f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
95f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka *
105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * See the License for the specific language governing permissions and
145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * limitations under the License.
155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */
165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokapackage com.android.inputmethod.keyboard;
185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
19d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaokaimport android.animation.AnimatorInflater;
2031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaokaimport android.animation.ObjectAnimator;
215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.Context;
2213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport android.content.SharedPreferences;
235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.pm.PackageManager;
244112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.content.res.TypedArray;
256dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport android.graphics.Canvas;
26f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaokaimport android.graphics.Color;
2722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaokaimport android.graphics.Paint;
284112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokaimport android.graphics.Paint.Align;
29bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaokaimport android.graphics.Typeface;
3013ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaokaimport android.preference.PreferenceManager;
315d2d852eb0caaf7416c159f83d51e07b1ca87e30Jean Chalardimport android.text.TextUtils;
325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.AttributeSet;
335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.Log;
345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.LayoutInflater;
355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.MotionEvent;
365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.View;
37b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaokaimport android.view.ViewGroup;
385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils;
404d146d5e3e00cab1cca7d0d29fe00c0d629b5eacTadashi G. Takaokaimport com.android.inputmethod.accessibility.MainKeyboardAccessibilityDelegate;
4115f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.ExternallyReferenced;
42cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.DrawingPreviewPlacerView;
4334a9e2ae87c6718d439b294d9536b6587a4f89f8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.DrawingProxy;
44cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureFloatingTextDrawingPreview;
45cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.GestureTrailsDrawingPreview;
4649d8af8a4e900f3c68c333aba7fde0a11fd368b1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyDrawParams;
47bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyPreviewChoreographer;
480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams;
49016d6c424cf004c282db5a57e64f3d1eee672a22Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyPreviewView;
5003288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.MoreKeySpec;
51b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper;
52cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview;
532fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport com.android.inputmethod.keyboard.internal.TimerHandler;
545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
5585ddfe1317a4475269e53f62c2338c335e02e839Jean Chalardimport com.android.inputmethod.latin.RichInputMethodSubtype;
56375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords;
579342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants;
585b91b551e5ffaf2c2e691dfbd434f21c82293986Jean Chalardimport com.android.inputmethod.latin.common.CoordinateUtils;
59a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.DebugSettings;
604934a88b618f06600e2d725a43bdd2511715b4caTadashi G. Takaokaimport com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils;
61ccf4a310279b13bbf0b6aac76a0878178c1dfb7dTadashi G. Takaokaimport com.android.inputmethod.latin.utils.TypefaceUtils;
625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
635d2d852eb0caaf7416c159f83d51e07b1ca87e30Jean Chalardimport java.util.Locale;
645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap;
655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
662ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaokaimport javax.annotation.Nonnull;
67051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaokaimport javax.annotation.Nullable;
682ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka
695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/**
705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements.
715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka *
722fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextRatio
732fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextColor
7441f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowRadius
752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowColor
76dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha
77dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFadeoutAnimator
78dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator
79dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator
80dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyHysteresisDistance
81dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdTime
82dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdDistance
832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_keySelectionByDraggingFinger
84dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatStartTimeout
85dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatInterval
86dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressKeyTimeout
87dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout
88dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout
89375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLayout
900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewOffset
910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewHeight
920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLingerTimeout
93ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewShowUpAnimator
94ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewDismissAnimator
95d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardLayout
960f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardForActionLayout
97f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_backgroundDimAlpha
98dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint
99375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureFloatingPreviewTextLingerTimeout
1003623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping
1013623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDetectFastMoveSpeedThreshold
1023623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicThresholdDecayDuration
1033623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdFrom
1043623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdTo
1053623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdFrom
1063623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdTo
1073623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureSamplingMinimumDistance
1083623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionMinimumTime
1093623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold
1103623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration
1115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */
11234a9e2ae87c6718d439b294d9536b6587a4f89f8Tadashi G. Takaokapublic final class MainKeyboardView extends KeyboardView implements DrawingProxy,
113be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka        MoreKeysPanel.Controller {
114c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String TAG = MainKeyboardView.class.getSimpleName();
1155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
116bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    /** Listener for {@link KeyboardActionListener}. */
117bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    private KeyboardActionListener mKeyboardActionListener;
118bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka
1192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    /* Space key and its icon and background. */
1204112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    private Key mSpaceKey;
121bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    // Stuff to draw language name on spacebar.
12231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    private final int mLanguageOnSpacebarFinalAlpha;
12331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator;
1247dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka    private int mLanguageOnSpacebarFormatType;
125fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka    private boolean mHasMultipleEnabledIMEsOrSubtypes;
1264daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang    private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE;
1272fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final float mLanguageOnSpacebarTextRatio;
1282fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private float mLanguageOnSpacebarTextSize;
1292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final int mLanguageOnSpacebarTextColor;
13041f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka    private final float mLanguageOnSpacebarTextShadowRadius;
1312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final int mLanguageOnSpacebarTextShadowColor;
13241f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka    private static final float LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
133bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    // The minimum x-scale to fit the language name on spacebar.
134bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f;
13515d4793911fa305e0a58aced925961e948582979satok
13673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka    // Stuff to draw altCodeWhileTyping keys.
1372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator;
1382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator;
1394daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang    private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE;
14073a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka
141cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    // Drawing preview placer view
142cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final DrawingPreviewPlacerView mDrawingPreviewPlacerView;
143375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private final int[] mOriginCoords = CoordinateUtils.newInstance();
144cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final GestureFloatingTextDrawingPreview mGestureFloatingTextDrawingPreview;
145cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final GestureTrailsDrawingPreview mGestureTrailsDrawingPreview;
146cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final SlidingKeyInputDrawingPreview mSlidingKeyInputDrawingPreview;
147375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
1480e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    // Key preview
149992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka    private final KeyPreviewDrawParams mKeyPreviewDrawParams;
150bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    private final KeyPreviewChoreographer mKeyPreviewChoreographer;
1510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
1522affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka    // More keys keyboard
153f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    private final Paint mBackgroundDimAlphaPaint = new Paint();
154a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka    private final View mMoreKeysKeyboardContainer;
1550f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka    private final View mMoreKeysKeyboardForActionContainer;
156a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka    private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = new WeakHashMap<>();
1572affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka    private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
158d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    // More keys panel (used by both more keys keyboard and more suggestions view)
159d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    // TODO: Consider extending to support multiple more keys panels
160d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    private MoreKeysPanel mMoreKeysPanel;
1615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
162375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    // Gesture floating preview text
163375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    // TODO: Make this parameter customizable by user via settings.
164375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private int mGestureFloatingPreviewTextLingerTimeout;
165375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
1662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final KeyDetector mKeyDetector;
167b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka    private final NonDistinctMultitouchHelper mNonDistinctMultitouchHelper;
1685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
1692ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka    private final TimerHandler mTimerHandler;
170741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private final int mLanguageOnSpacebarHorizontalMargin;
1715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
172d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka    private MainKeyboardAccessibilityDelegate mAccessibilityDelegate;
173bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka
174dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public MainKeyboardView(final Context context, final AttributeSet attrs) {
175c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        this(context, attrs, R.attr.mainKeyboardViewStyle);
1765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
1775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
178dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) {
1795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        super(context, attrs, defStyle);
1805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
181be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka        final DrawingPreviewPlacerView drawingPreviewPlacerView =
182be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka                new DrawingPreviewPlacerView(context, attrs);
1832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
1842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes(
1852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView);
1862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int ignoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt(
1872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0);
1882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int gestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt(
1892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0);
1902ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mTimerHandler = new TimerHandler(
1912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                this, ignoreAltCodeKeyTimeout, gestureRecognitionUpdateTime);
1922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
1932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension(
1942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f);
1952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension(
1962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f);
1972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mKeyDetector = new KeyDetector(
1982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier);
1992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
2002ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        PointerTracker.init(mainKeyboardViewAttr, mTimerHandler, this /* DrawingProxy */);
2012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
20213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
20313ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final boolean forceNonDistinctMultitouch = prefs.getBoolean(
204a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka                DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false);
20513ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final boolean hasDistinctMultitouch = context.getPackageManager()
206b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)
207b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                && !forceNonDistinctMultitouch;
208b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        mNonDistinctMultitouchHelper = hasDistinctMultitouch ? null
209921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka                : new NonDistinctMultitouchHelper();
21022b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka
211f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        final int backgroundDimAlpha = mainKeyboardViewAttr.getInt(
212f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka                R.styleable.MainKeyboardView_backgroundDimAlpha, 0);
213f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        mBackgroundDimAlphaPaint.setColor(Color.BLACK);
214f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha);
2152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextRatio = mainKeyboardViewAttr.getFraction(
2162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f);
2172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextColor = mainKeyboardViewAttr.getColor(
2182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextColor, 0);
21941f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka        mLanguageOnSpacebarTextShadowRadius = mainKeyboardViewAttr.getFloat(
22041f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarTextShadowRadius,
22141f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka                LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED);
2222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextShadowColor = mainKeyboardViewAttr.getColor(
2232fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextShadowColor, 0);
224d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt(
225c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha,
2264daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang                Constants.Color.ALPHA_OPAQUE);
227d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int languageOnSpacebarFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId(
228c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0);
229d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int altCodeKeyWhileTypingFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId(
230c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0);
231d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int altCodeKeyWhileTypingFadeinAnimatorResId = mainKeyboardViewAttr.getResourceId(
232c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0);
233160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka
234992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka        mKeyPreviewDrawParams = new KeyPreviewDrawParams(mainKeyboardViewAttr);
235bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer = new KeyPreviewChoreographer(mKeyPreviewDrawParams);
236bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
237a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId(
238d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka                R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0);
2390f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        final int moreKeysKeyboardForActionLayoutId = mainKeyboardViewAttr.getResourceId(
2400f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka                R.styleable.MainKeyboardView_moreKeysKeyboardForActionLayout,
2410f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka                moreKeysKeyboardLayoutId);
242d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean(
243c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false);
244375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
245375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mGestureFloatingPreviewTextLingerTimeout = mainKeyboardViewAttr.getInt(
246375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka                R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0);
247fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
248cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview = new GestureFloatingTextDrawingPreview(
2497fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka                mainKeyboardViewAttr);
250be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.setDrawingView(drawingPreviewPlacerView);
251fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
2527fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mGestureTrailsDrawingPreview = new GestureTrailsDrawingPreview(mainKeyboardViewAttr);
253be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setDrawingView(drawingPreviewPlacerView);
254fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
2557fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview = new SlidingKeyInputDrawingPreview(mainKeyboardViewAttr);
256be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.setDrawingView(drawingPreviewPlacerView);
257d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mainKeyboardViewAttr.recycle();
258160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka
259be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka        mDrawingPreviewPlacerView = drawingPreviewPlacerView;
260be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka
2610f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(getContext());
2620f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        mMoreKeysKeyboardContainer = inflater.inflate(moreKeysKeyboardLayoutId, null);
2630f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        mMoreKeysKeyboardForActionContainer = inflater.inflate(
2640f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka                moreKeysKeyboardForActionLayoutId, null);
26531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator(
26631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                languageOnSpacebarFadeoutAnimatorResId, this);
26731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator(
26831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                altCodeKeyWhileTypingFadeoutAnimatorResId, this);
26931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator(
27031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                altCodeKeyWhileTypingFadeinAnimatorResId, this);
271f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka
272f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka        mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
273741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka
2742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarHorizontalMargin = (int)getResources().getDimension(
2752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.dimen.config_language_on_spacebar_horizontal_margin);
27631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
27731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
27852876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    @Override
27952876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
28052876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa        super.setHardwareAcceleratedDrawingEnabled(enabled);
281cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mDrawingPreviewPlacerView.setHardwareAcceleratedDrawingEnabled(enabled);
28252876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    }
28352876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa
284dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    private ObjectAnimator loadObjectAnimator(final int resId, final Object target) {
28520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (resId == 0) {
28657372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka            // TODO: Stop returning null.
28720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return null;
28820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
28931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator(
29031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                getContext(), resId);
291d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka        if (animator != null) {
29231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka            animator.setTarget(target);
29373a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka        }
29431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return animator;
29531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
29673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka
2972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel,
2982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            final ObjectAnimator animatorToStart) {
2992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (animatorToCancel == null || animatorToStart == null) {
3002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            // TODO: Stop using null as a no-operation animator.
3012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return;
3022fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
3032fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        float startFraction = 0.0f;
3042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (animatorToCancel.isStarted()) {
3052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            animatorToCancel.cancel();
3062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            startFraction = 1.0f - animatorToCancel.getAnimatedFraction();
3072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
3082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final long startTime = (long)(animatorToStart.getDuration() * startFraction);
3092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        animatorToStart.start();
3102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        animatorToStart.setCurrentPlayTime(startTime);
3112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
3122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
313be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka    // Implements {@link DrawingProxy#startWhileTypingAnimation(int)}.
314051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka    /**
315051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka     * Called when a while-typing-animation should be started.
316be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka     * @param fadeInOrOut {@link DrawingProxy#FADE_IN} starts while-typing-fade-in animation.
317be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka     * {@link DrawingProxy#FADE_OUT} starts while-typing-fade-out animation.
318051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka     */
3192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
320051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka    public void startWhileTypingAnimation(final int fadeInOrOut) {
321051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka        switch (fadeInOrOut) {
322be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka        case DrawingProxy.FADE_IN:
323051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka            cancelAndStartAnimators(
324051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka                    mAltCodeKeyWhileTypingFadeoutAnimator, mAltCodeKeyWhileTypingFadeinAnimator);
325051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka            break;
326be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka        case DrawingProxy.FADE_OUT:
327051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka            cancelAndStartAnimators(
328051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka                    mAltCodeKeyWhileTypingFadeinAnimator, mAltCodeKeyWhileTypingFadeoutAnimator);
329051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka            break;
330051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka        }
3312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
3322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
33315f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
33431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    public int getLanguageOnSpacebarAnimAlpha() {
33531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return mLanguageOnSpacebarAnimAlpha;
336d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka    }
337d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka
33815f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
339dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setLanguageOnSpacebarAnimAlpha(final int alpha) {
34031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mLanguageOnSpacebarAnimAlpha = alpha;
34131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        invalidateKey(mSpaceKey);
34231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
34331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
34415f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
34531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    public int getAltCodeKeyWhileTypingAnimAlpha() {
34631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return mAltCodeKeyWhileTypingAnimAlpha;
34731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
34831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
34915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
350dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) {
3515141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        if (mAltCodeKeyWhileTypingAnimAlpha == alpha) {
3525141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            return;
3535141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3545141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        // Update the visual of alt-code-key-while-typing.
35531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingAnimAlpha = alpha;
3565141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        final Keyboard keyboard = getKeyboard();
3575141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        if (keyboard == null) {
3585141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            return;
3595141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3605141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        for (final Key key : keyboard.mAltCodeKeysWhileTyping) {
3615141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            invalidateKey(key);
3625141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
365dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setKeyboardActionListener(final KeyboardActionListener listener) {
3665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        mKeyboardActionListener = listener;
3675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka        PointerTracker.setKeyboardActionListener(listener);
3685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
3702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // TODO: We should reconsider which coordinate system should be used to represent keyboard
3712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // event.
3722fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public int getKeyX(final int x) {
3732fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return Constants.isValidCoordinate(x) ? mKeyDetector.getTouchX(x) : x;
3745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
3762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // TODO: We should reconsider which coordinate system should be used to represent keyboard
3772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // event.
3782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public int getKeyY(final int y) {
3792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return Constants.isValidCoordinate(y) ? mKeyDetector.getTouchY(y) : y;
3800efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka    }
3810efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka
3825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    /**
3835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * Attaches a keyboard to this view. The keyboard can be switched at any time and the
3845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * view will re-layout itself to accommodate the keyboard.
3855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @see Keyboard
3865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @see #getKeyboard()
3875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @param keyboard the keyboard to display in this view
3885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     */
3895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
390dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setKeyboard(final Keyboard keyboard) {
3915cbda70956af14453fca7395d892c59aabbd8fd3Jean Chalard        // Remove any pending messages, except dismissing preview and key repeat.
3922ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mTimerHandler.cancelLongPressTimers();
3935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        super.setKeyboard(keyboard);
3945a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka        mKeyDetector.setKeyboard(
39508ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
3968335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        PointerTracker.setKeyDetector(mKeyDetector);
397a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        mMoreKeysKeyboardCache.clear();
3984112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
399240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka        mSpaceKey = keyboard.getKey(Constants.CODE_SPACE);
4004112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
4012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextSize = keyHeight * mLanguageOnSpacebarTextRatio;
402f147794fd41491a3383e6aca6d49007f58124068alanv
403d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
404dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka            if (mAccessibilityDelegate == null) {
405dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka                mAccessibilityDelegate = new MainKeyboardAccessibilityDelegate(this, mKeyDetector);
406dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka            }
407ae0fab9550f1d9159d819dbb0b7cc86c2bf2937cTadashi G. Takaoka            mAccessibilityDelegate.setKeyboard(keyboard);
408d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        } else {
409ae0fab9550f1d9159d819dbb0b7cc86c2bf2937cTadashi G. Takaoka            mAccessibilityDelegate = null;
410d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        }
4115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
4125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
4130e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    /**
414ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * Enables or disables the key preview popup. This is a popup that shows a magnified
4150e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * version of the depressed key. By default the preview is enabled.
4160e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * @param previewEnabled whether or not to enable the key feedback preview
4170e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * @param delay the delay after which the preview is dismissed
4180e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     */
4190e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) {
4207d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka        mKeyPreviewDrawParams.setPopupEnabled(previewEnabled, delay);
4210e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
4220e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
423ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    /**
424ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * Enables or disables the key preview popup animations and set animations' parameters.
425ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     *
426ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param hasCustomAnimationParams false to use the default key preview popup animations
427ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     *   specified by keyPreviewShowUpAnimator and keyPreviewDismissAnimator attributes.
428ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     *   true to override the default animations with the specified parameters.
429ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param showUpStartXScale from this x-scale the show up animation will start.
430ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param showUpStartYScale from this y-scale the show up animation will start.
431ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param showUpDuration the duration of the show up animation in milliseconds.
432ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param dismissEndXScale to this x-scale the dismiss animation will end.
433ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param dismissEndYScale to this y-scale the dismiss animation will end.
434ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param dismissDuration the duration of the dismiss animation in milliseconds.
435ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     */
436ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    public void setKeyPreviewAnimationParams(final boolean hasCustomAnimationParams,
437ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration,
438ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) {
439ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        mKeyPreviewDrawParams.setAnimationParams(hasCustomAnimationParams,
440ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                showUpStartXScale, showUpStartYScale, showUpDuration,
441ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                dismissEndXScale, dismissEndYScale, dismissDuration);
442276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka    }
443276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka
444375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private void locatePreviewPlacerView() {
445375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        getLocationInWindow(mOriginCoords);
4460c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        mDrawingPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, getWidth(), getHeight());
4470c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka    }
4480c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka
4490c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka    private void installPreviewPlacerView() {
450375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        final View rootView = getRootView();
451375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        if (rootView == null) {
452375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka            Log.w(TAG, "Cannot find root view");
453375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka            return;
454375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        }
455375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content);
456375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        // Note: It'd be very weird if we get null by android.R.id.content.
457375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        if (windowContentView == null) {
458cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka            Log.w(TAG, "Cannot find android.R.id.content view to add DrawingPreviewPlacerView");
4590c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka            return;
460375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        }
4610c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        windowContentView.addView(mDrawingPreviewPlacerView);
462375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
463375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
46453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    // Implements {@link DrawingProxy#onKeyPressed(Key,boolean)}.
4650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
46653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    public void onKeyPressed(@Nonnull final Key key, final boolean withPreview) {
46753b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        key.onPressed();
46853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        invalidateKey(key);
46953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        if (withPreview && !key.noKeyPreview()) {
47053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka            showKeyPreview(key);
4710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        }
47253b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    }
47353b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka
47453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    private void showKeyPreview(@Nonnull final Key key) {
4752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final Keyboard keyboard = getKeyboard();
476a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        if (keyboard == null) {
477a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka            return;
478a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        }
479a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams;
4807d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka        if (!previewParams.isPopupEnabled()) {
481992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka            previewParams.setVisibleOffset(-keyboard.mVerticalGap);
4822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return;
4832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
4842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
485bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        locatePreviewPlacerView();
4860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        getLocationInWindow(mOriginCoords);
4879d5d01a54319797db17fa8ac4b612f8836c83b9aTadashi G. Takaoka        mKeyPreviewChoreographer.placeAndShowKeyPreview(key, keyboard.mIconsSet, getKeyDrawParams(),
4883ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka                getWidth(), mOriginCoords, mDrawingPreviewPlacerView, isHardwareAccelerated());
4892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
4902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
49153b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    private void dismissKeyPreviewWithoutDelay(@Nonnull final Key key) {
492bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer.dismissKeyPreview(key, false /* withAnimation */);
4932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        invalidateKey(key);
4942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
4952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
49653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    // Implements {@link DrawingProxy#onKeyReleased(Key,boolean)}.
4972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
49853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    public void onKeyReleased(@Nonnull final Key key, final boolean withAnimation) {
49953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        key.onReleased();
50053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        invalidateKey(key);
50153b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        if (!key.noKeyPreview()) {
50253b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka            if (withAnimation) {
50353b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka                dismissKeyPreview(key);
50453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka            } else {
50553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka                dismissKeyPreviewWithoutDelay(key);
50653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka            }
50753b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        }
50853b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    }
50953b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka
51053b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    private void dismissKeyPreview(@Nonnull final Key key) {
5112ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        if (isHardwareAccelerated()) {
512d2c00f550d6b4f2452fe38cee7c1d2222a4b4b3dTadashi G. Takaoka            mKeyPreviewChoreographer.dismissKeyPreview(key, true /* withAnimation */);
513d2c00f550d6b4f2452fe38cee7c1d2222a4b4b3dTadashi G. Takaoka            return;
5142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
5152ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        // TODO: Implement preference option to control key preview method and duration.
5162ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mTimerHandler.postDismissKeyPreview(key, mKeyPreviewDrawParams.getLingerTimeout());
5170e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
5180e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
519ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka    public void setSlidingKeyInputPreviewEnabled(final boolean enabled) {
520cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.setPreviewEnabled(enabled);
521ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka    }
522ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka
5230e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
524be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka    public void showSlidingKeyInputPreview(@Nullable final PointerTracker tracker) {
5250e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        locatePreviewPlacerView();
526051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka        if (tracker != null) {
527051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka            mSlidingKeyInputDrawingPreview.setPreviewPosition(tracker);
528051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka        } else {
529051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka            mSlidingKeyInputDrawingPreview.dismissSlidingKeyInputPreview();
530051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka        }
5310e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
5320e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
533724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa    private void setGesturePreviewMode(final boolean isGestureTrailEnabled,
534724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureFloatingPreviewTextEnabled) {
535cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.setPreviewEnabled(isGestureFloatingPreviewTextEnabled);
536cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setPreviewEnabled(isGestureTrailEnabled);
537375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
538375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
5392ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka    public void showGestureFloatingPreviewText(@Nonnull final SuggestedWords suggestedWords,
5402ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka            final boolean dismissDelayed) {
541375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        locatePreviewPlacerView();
5422ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        final GestureFloatingTextDrawingPreview gestureFloatingTextDrawingPreview =
5432ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka                mGestureFloatingTextDrawingPreview;
5442ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        gestureFloatingTextDrawingPreview.setSuggetedWords(suggestedWords);
5452ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        if (dismissDelayed) {
5462ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka            mTimerHandler.postDismissGestureFloatingPreviewText(
5472ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka                    mGestureFloatingPreviewTextLingerTimeout);
5482ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        }
549375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
550375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
551be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka    // Implements {@link DrawingProxy#dismissGestureFloatingPreviewTextWithoutDelay()}.
5522ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka    @Override
5532ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka    public void dismissGestureFloatingPreviewTextWithoutDelay() {
5542ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.dismissGestureFloatingPreviewText();
555375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
556375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
557fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka    @Override
558be708c4e59ba16cf735440b99aa682baa3319ec5Tadashi G. Takaoka    public void showGestureTrail(@Nonnull final PointerTracker tracker,
559212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka            final boolean showsFloatingPreviewText) {
560375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        locatePreviewPlacerView();
561212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka        if (showsFloatingPreviewText) {
562cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka            mGestureFloatingTextDrawingPreview.setPreviewPosition(tracker);
563212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka        }
564cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setPreviewPosition(tracker);
565375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
566375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
5678335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka    // Note that this method is called from a non-UI thread.
568c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka    @SuppressWarnings("static-method")
569dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) {
5708335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable);
5718335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka    }
5728335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka
573724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa    public void setGestureHandlingEnabledByUser(final boolean isGestureHandlingEnabledByUser,
574724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureTrailEnabled,
575724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureFloatingPreviewTextEnabled) {
576724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa        PointerTracker.setGestureHandlingEnabledByUser(isGestureHandlingEnabledByUser);
577724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa        setGesturePreviewMode(isGestureHandlingEnabledByUser && isGestureTrailEnabled,
578724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa                isGestureHandlingEnabledByUser && isGestureFloatingPreviewTextEnabled);
5790657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka    }
5800657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka
5815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
5824331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    protected void onAttachedToWindow() {
5834331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        super.onAttachedToWindow();
5840c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        installPreviewPlacerView();
585c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    }
586c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka
587c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    @Override
588c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    protected void onDetachedFromWindow() {
589c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka        super.onDetachedFromWindow();
590cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mDrawingPreviewPlacerView.removeAllViews();
5914331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
5924331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
59353b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    // Implements {@link DrawingProxy@showMoreKeysKeyboard(Key,PointerTracker)}.
59453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    @Override
59553b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    @Nullable
59653b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka    public MoreKeysPanel showMoreKeysKeyboard(@Nonnull final Key key,
59753b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka            @Nonnull final PointerTracker tracker) {
59803288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        final MoreKeySpec[] moreKeys = key.getMoreKeys();
59903288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        if (moreKeys == null) {
6005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka            return null;
60120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
602a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key);
603a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (moreKeysKeyboard == null) {
60403288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link KeyPreviewDrawParams#mPreviewVisibleWidth} should have been set at
60503288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link KeyPreviewChoreographer#placeKeyPreview(Key,TextView,KeyboardIconsSet,KeyDrawParams,int,int[]},
60603288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // though there may be some chances that the value is zero. <code>width == 0</code>
60703288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // will cause zero-division error at
60803288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link MoreKeysKeyboardParams#setParameters(int,int,int,int,int,int,boolean,int)}.
60984405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka            final boolean isSingleMoreKeyWithPreview = mKeyPreviewDrawParams.isPopupEnabled()
61003288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    && !key.noKeyPreview() && moreKeys.length == 1
61103288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    && mKeyPreviewDrawParams.getVisibleWidth() > 0;
61203288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            final MoreKeysKeyboard.Builder builder = new MoreKeysKeyboard.Builder(
61353b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka                    getContext(), key, getKeyboard(), isSingleMoreKeyWithPreview,
61403288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    mKeyPreviewDrawParams.getVisibleWidth(),
61503288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    mKeyPreviewDrawParams.getVisibleHeight(), newLabelPaint(key));
61603288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            moreKeysKeyboard = builder.build();
617a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka            mMoreKeysKeyboardCache.put(key, moreKeysKeyboard);
61820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
6195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
6200f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        final View container = key.isActionKey() ? mMoreKeysKeyboardForActionContainer
6210f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka                : mMoreKeysKeyboardContainer;
6222affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        final MoreKeysKeyboardView moreKeysKeyboardView =
6232affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka                (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view);
6242affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        moreKeysKeyboardView.setKeyboard(moreKeysKeyboard);
625b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka        container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
62663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka
627547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka        final int[] lastCoords = CoordinateUtils.newInstance();
628547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka        tracker.getLastCoordinates(lastCoords);
62903288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        final boolean keyPreviewEnabled = mKeyPreviewDrawParams.isPopupEnabled()
63003288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                && !key.noKeyPreview();
6317ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // The more keys keyboard is usually horizontally aligned with the center of the parent key.
6327ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more
6337ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // keys keyboard is placed at the touch point of the parent key.
6347ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled)
635547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka                ? CoordinateUtils.x(lastCoords)
6367dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka                : key.getX() + key.getWidth() / 2;
6377ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // The more keys keyboard is usually vertically aligned with the top edge of the parent key
6387ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically
6397ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // aligned with the bottom edge of the visible part of the key preview.
64029d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka        // {@code mPreviewVisibleOffset} has been set appropriately in
64129d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka        // {@link KeyboardView#showKeyPreview(PointerTracker)}.
642992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka        final int pointY = key.getY() + mKeyPreviewDrawParams.getVisibleOffset();
64353b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        moreKeysKeyboardView.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener);
64453b6d627e7fe66ce47ee6ae01254abc070558e77Tadashi G. Takaoka        return moreKeysKeyboardView;
6455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
6465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
6472fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public boolean isInDraggingFinger() {
648a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (isShowingMoreKeysPanel()) {
64963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka            return true;
6505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        }
6512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return PointerTracker.isAnyInDraggingFinger();
6525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
6535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
654d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
655d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    public void onShowMoreKeysPanel(final MoreKeysPanel panel) {
6561b6eea89037158a1e271730eacdacb8b6e550d3aTadashi G. Takaoka        locatePreviewPlacerView();
657ca6e5dfedbb57f6ec31880f2799b40a6b2adadbcTadashi G. Takaoka        // Dismiss another {@link MoreKeysPanel} that may be being showed.
658ca6e5dfedbb57f6ec31880f2799b40a6b2adadbcTadashi G. Takaoka        onDismissMoreKeysPanel();
659ca6e5dfedbb57f6ec31880f2799b40a6b2adadbcTadashi G. Takaoka        // Dismiss all key previews that may be being showed.
660ca6e5dfedbb57f6ec31880f2799b40a6b2adadbcTadashi G. Takaoka        PointerTracker.setReleasedKeyGraphicsToAllKeys();
661051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka        // Dismiss sliding key input preview that may be being showed.
662051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.dismissSlidingKeyInputPreview();
663cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        panel.showInParent(mDrawingPreviewPlacerView);
664d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mMoreKeysPanel = panel;
665d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
666d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
667d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    public boolean isShowingMoreKeysPanel() {
668a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        return mMoreKeysPanel != null && mMoreKeysPanel.isShowingInParent();
669d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
670d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
671d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
6721f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka    public void onCancelMoreKeysPanel() {
673d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        PointerTracker.dismissAllMoreKeysPanels();
674d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
675d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
676d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
6771f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka    public void onDismissMoreKeysPanel() {
678d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        if (isShowingMoreKeysPanel()) {
6797f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka            mMoreKeysPanel.removeFromParent();
680d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka            mMoreKeysPanel = null;
681d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        }
682d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
683d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
6845433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public void startDoubleTapShiftKeyTimer() {
6852ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mTimerHandler.startDoubleTapShiftKeyTimer();
6865433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
6875433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
6885433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public void cancelDoubleTapShiftKeyTimer() {
6892ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mTimerHandler.cancelDoubleTapShiftKeyTimer();
6905433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
6915433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
6925433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public boolean isInDoubleTapShiftKeyTimeout() {
6932ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        return mTimerHandler.isInDoubleTapShiftKeyTimeout();
6945433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
6955433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
6965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
69712d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic    public boolean onTouchEvent(final MotionEvent event) {
69846286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka        if (getKeyboard() == null) {
69946286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka            return false;
70046286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka        }
701b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        if (mNonDistinctMultitouchHelper != null) {
70212d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic            if (event.getPointerCount() > 1 && mTimerHandler.isInKeyRepeat()) {
703b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                // Key repeating timer will be canceled if 2 or more keys are in action.
7042ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka                mTimerHandler.cancelKeyRepeatTimers();
705b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            }
706b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            // Non distinct multitouch screen support
70712d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic            mNonDistinctMultitouchHelper.processMotionEvent(event, mKeyDetector);
708b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            return true;
709b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        }
71012d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic        return processMotionEvent(event);
711c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka    }
712c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka
71312d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic    public boolean processMotionEvent(final MotionEvent event) {
71412d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic        final int index = event.getActionIndex();
71512d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic        final int id = event.getPointerId(index);
7162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final PointerTracker tracker = PointerTracker.getPointerTracker(id);
7172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // When a more keys panel is showing, we should ignore other fingers' single touch events
7182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // other than the finger that is showing the more keys panel.
7192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (isShowingMoreKeysPanel() && !tracker.isShowingMoreKeysPanel()
7202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                && PointerTracker.getActivePointerTrackerCount() == 1) {
7212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return true;
7222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
72312d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic        tracker.processMotionEvent(event, mKeyDetector);
7245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        return true;
7255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
7265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
7275c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka    public void cancelAllOngoingEvents() {
7282ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mTimerHandler.cancelAllMessages();
729ca6e5dfedbb57f6ec31880f2799b40a6b2adadbcTadashi G. Takaoka        PointerTracker.setReleasedKeyGraphicsToAllKeys();
7302ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.dismissGestureFloatingPreviewText();
731051f8b144232f724386960cf6781a6d4665e4f02Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.dismissSlidingKeyInputPreview();
7325c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        PointerTracker.dismissAllMoreKeysPanels();
7335c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        PointerTracker.cancelAllPointerTrackers();
734375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
735375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
7365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    public void closing() {
7375c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        cancelAllOngoingEvents();
738a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        mMoreKeysKeyboardCache.clear();
7395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
7405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
741bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka    public void onHideWindow() {
742a74719c934ceb30d2afb7ae999c909f5c6fd5325Tadashi G. Takaoka        onDismissMoreKeysPanel();
743d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
74404cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka        if (accessibilityDelegate != null
74504cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka                && AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
746d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka            accessibilityDelegate.onHideWindow();
7471ead609e6fd64fd5ac2979ac3802d8bada7d7f49Tadashi G. Takaoka        }
748bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka    }
749bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka
750586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette    /**
7519647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka     * {@inheritDoc}
752586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette     */
753c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka    @Override
7549647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka    public boolean onHoverEvent(final MotionEvent event) {
755d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
75604cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka        if (accessibilityDelegate != null
75704cd8794e04b14c2b7e7eed036b83075792134a1Tadashi G. Takaoka                && AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
758d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka            return accessibilityDelegate.onHoverEvent(event);
7595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        }
7609647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka        return super.onHoverEvent(event);
7615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
76222b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka
763dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void updateShortcutKey(final boolean available) {
7647bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        final Keyboard keyboard = getKeyboard();
76520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (keyboard == null) {
76620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return;
76720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
768240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka        final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT);
76920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (shortcutKey == null) {
77020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return;
77120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
7727bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        shortcutKey.setEnabled(available);
7737bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        invalidateKey(shortcutKey);
7745afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka    }
7755afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka
776dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged,
7777dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            final int languageOnSpacebarFormatType,
7787dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            final boolean hasMultipleEnabledIMEsOrSubtypes) {
779016d6c424cf004c282db5a57e64f3d1eee672a22Tadashi G. Takaoka        if (subtypeChanged) {
780016d6c424cf004c282db5a57e64f3d1eee672a22Tadashi G. Takaoka            KeyPreviewView.clearTextCache();
781016d6c424cf004c282db5a57e64f3d1eee672a22Tadashi G. Takaoka        }
7827dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka        mLanguageOnSpacebarFormatType = languageOnSpacebarFormatType;
783fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka        mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes;
784fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka        final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator;
785d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka        if (animator == null) {
7864934a88b618f06600e2d725a43bdd2511715b4caTadashi G. Takaoka            mLanguageOnSpacebarFormatType = LanguageOnSpacebarUtils.FORMAT_TYPE_NONE;
7874c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka        } else {
7887dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            if (subtypeChanged
7894934a88b618f06600e2d725a43bdd2511715b4caTadashi G. Takaoka                    && languageOnSpacebarFormatType != LanguageOnSpacebarUtils.FORMAT_TYPE_NONE) {
7904daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang                setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE);
79131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                if (animator.isStarted()) {
79231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                    animator.cancel();
79331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                }
794d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka                animator.start();
795dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka            } else {
79631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                if (!animator.isStarted()) {
79731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                    mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha;
79831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                }
799dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka            }
8004c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka        }
8014112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        invalidateKey(mSpaceKey);
8024112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    }
8034112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
80422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka    @Override
805dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint,
806dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka            final KeyDrawParams params) {
8076bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka        if (key.altCodeWhileTyping() && key.isEnabled()) {
80873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka            params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha;
80973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka        }
81041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        super.onDrawKeyTopVisuals(key, canvas, paint, params);
8117dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int code = key.getCode();
8127dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        if (code == Constants.CODE_SPACE) {
81341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            // If input language are explicitly selected.
8144934a88b618f06600e2d725a43bdd2511715b4caTadashi G. Takaoka            if (mLanguageOnSpacebarFormatType != LanguageOnSpacebarUtils.FORMAT_TYPE_NONE) {
81541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka                drawLanguageOnSpacebar(key, canvas, paint);
81641808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            }
8174112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka            // Whether space key needs to show the "..." popup hint for special purposes
818fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka            if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) {
819bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka                drawKeyPopupHint(key, canvas, paint, params);
8204112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka            }
8217dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        } else if (code == Constants.CODE_LANGUAGE_SWITCH) {
822fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka            drawKeyPopupHint(key, canvas, paint, params);
82322b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka        }
82422b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka    }
8254112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
826741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private boolean fitsTextIntoWidth(final int width, final String text, final Paint paint) {
827741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka        final int maxTextWidth = width - mLanguageOnSpacebarHorizontalMargin * 2;
828bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        paint.setTextScaleX(1.0f);
8292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float textWidth = TypefaceUtils.getStringWidth(text, paint);
83020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (textWidth < width) {
83120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return true;
83220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
833bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
834741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka        final float scaleX = maxTextWidth / textWidth;
83520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) {
83620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return false;
83720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
838bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
839bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        paint.setTextScaleX(scaleX);
8402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return TypefaceUtils.getStringWidth(text, paint) < maxTextWidth;
841bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    }
842bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
843bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    // Layout language name on spacebar.
844741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private String layoutLanguageOnSpacebar(final Paint paint,
84585ddfe1317a4475269e53f62c2338c335e02e839Jean Chalard            final RichInputMethodSubtype subtype, final int width) {
846bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        // Choose appropriate language name to fit into the width.
8474934a88b618f06600e2d725a43bdd2511715b4caTadashi G. Takaoka        if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarUtils.FORMAT_TYPE_FULL_LOCALE) {
84885ddfe1317a4475269e53f62c2338c335e02e839Jean Chalard            final String fullText = subtype.getFullDisplayName();
8497dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            if (fitsTextIntoWidth(width, fullText, paint)) {
8507dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka                return fullText;
8517dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            }
852bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        }
853bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
85485ddfe1317a4475269e53f62c2338c335e02e839Jean Chalard        final String middleText = subtype.getMiddleDisplayName();
85520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (fitsTextIntoWidth(width, middleText, paint)) {
85620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return middleText;
8574112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        }
8584112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
859bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        return "";
8604112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    }
8614112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
86241808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka    private void drawLanguageOnSpacebar(final Key key, final Canvas canvas, final Paint paint) {
863a66069abd83900b5f6b5333756d67e93b6edb3c1Tadashi G. Takaoka        final Keyboard keyboard = getKeyboard();
864a66069abd83900b5f6b5333756d67e93b6edb3c1Tadashi G. Takaoka        if (keyboard == null) {
865a66069abd83900b5f6b5333756d67e93b6edb3c1Tadashi G. Takaoka            return;
866a66069abd83900b5f6b5333756d67e93b6edb3c1Tadashi G. Takaoka        }
8677dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int width = key.getWidth();
8687dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int height = key.getHeight();
86941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTextAlign(Align.CENTER);
87041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTypeface(Typeface.DEFAULT);
87141808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTextSize(mLanguageOnSpacebarTextSize);
872a66069abd83900b5f6b5333756d67e93b6edb3c1Tadashi G. Takaoka        final String language = layoutLanguageOnSpacebar(paint, keyboard.mId.mSubtype, width);
87341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        // Draw language text with shadow
87441808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final float descent = paint.descent();
87541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final float textHeight = -paint.ascent() + descent;
87641808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final float baseline = height / 2 + textHeight / 2;
87741808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        if (mLanguageOnSpacebarTextShadowRadius > 0.0f) {
87841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            paint.setShadowLayer(mLanguageOnSpacebarTextShadowRadius, 0, 0,
87941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka                    mLanguageOnSpacebarTextShadowColor);
88041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        } else {
88141f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka            paint.clearShadowLayer();
8824112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        }
88341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setColor(mLanguageOnSpacebarTextColor);
88441808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setAlpha(mLanguageOnSpacebarAnimAlpha);
88541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        canvas.drawText(language, width / 2, baseline - descent, paint);
88641808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.clearShadowLayer();
88741808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTextScaleX(1.0f);
8884112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    }
889c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa
890e68d565d0f9704145adbf781105f1ac9a90f0a98Ken Wakasa    @Override
891c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa    public void deallocateMemory() {
892e68d565d0f9704145adbf781105f1ac9a90f0a98Ken Wakasa        super.deallocateMemory();
893afca1ddd233c03d79433931a0b6ba97ed22663edTadashi G. Takaoka        mDrawingPreviewPlacerView.deallocateMemory();
894c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa    }
8955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka}
896