MainKeyboardView.java revision 84405d2a6815a99992849e821e073835f2d892e3
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;
315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.AttributeSet;
325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.Log;
335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.LayoutInflater;
345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.MotionEvent;
355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.View;
36b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaokaimport android.view.ViewGroup;
37f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype;
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;
422fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport com.android.inputmethod.keyboard.internal.DrawingHandler;
43cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.DrawingPreviewPlacerView;
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;
497dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper;
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;
544daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport com.android.inputmethod.latin.Constants;
555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
56375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords;
57a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.DebugSettings;
58e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CoordinateUtils;
599364d46ac3590d23b8117a66efc8756454cef772Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.SpacebarLanguageUtils;
60ccf4a310279b13bbf0b6aac76a0878178c1dfb7dTadashi G. Takaokaimport com.android.inputmethod.latin.utils.TypefaceUtils;
615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap;
635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/**
655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements.
665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka *
672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextRatio
682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextColor
6941f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowRadius
702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowColor
71dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha
72dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFadeoutAnimator
73dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator
74dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator
75dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyHysteresisDistance
76dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdTime
77dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdDistance
782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_keySelectionByDraggingFinger
79dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatStartTimeout
80dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatInterval
81dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressKeyTimeout
82dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout
83dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout
84375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLayout
850e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewOffset
860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewHeight
870e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLingerTimeout
88d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardLayout
89f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_backgroundDimAlpha
90dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint
91375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureFloatingPreviewTextLingerTimeout
923623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping
933623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDetectFastMoveSpeedThreshold
943623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicThresholdDecayDuration
953623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdFrom
963623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdTo
973623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdFrom
983623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdTo
993623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureSamplingMinimumDistance
1003623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionMinimumTime
1013623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold
1023623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration
1035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */
1042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasapublic final class MainKeyboardView extends KeyboardView implements PointerTracker.DrawingProxy,
1052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        MoreKeysPanel.Controller, DrawingHandler.Callbacks, TimerHandler.Callbacks {
106c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String TAG = MainKeyboardView.class.getSimpleName();
1075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
108bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    /** Listener for {@link KeyboardActionListener}. */
109bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    private KeyboardActionListener mKeyboardActionListener;
110bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka
1112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    /* Space key and its icon and background. */
1124112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    private Key mSpaceKey;
113bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    // Stuff to draw language name on spacebar.
11431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    private final int mLanguageOnSpacebarFinalAlpha;
11531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator;
1167dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka    private int mLanguageOnSpacebarFormatType;
117fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka    private boolean mHasMultipleEnabledIMEsOrSubtypes;
1184daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang    private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE;
1192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final float mLanguageOnSpacebarTextRatio;
1202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private float mLanguageOnSpacebarTextSize;
1212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final int mLanguageOnSpacebarTextColor;
12241f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka    private final float mLanguageOnSpacebarTextShadowRadius;
1232fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final int mLanguageOnSpacebarTextShadowColor;
12441f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka    private static final float LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
125bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    // The minimum x-scale to fit the language name on spacebar.
126bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f;
12715d4793911fa305e0a58aced925961e948582979satok
12873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka    // Stuff to draw altCodeWhileTyping keys.
1292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator;
1302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator;
1314daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang    private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE;
13273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka
133cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    // Drawing preview placer view
134cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final DrawingPreviewPlacerView mDrawingPreviewPlacerView;
135375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private final int[] mOriginCoords = CoordinateUtils.newInstance();
136cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final GestureFloatingTextDrawingPreview mGestureFloatingTextDrawingPreview;
137cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final GestureTrailsDrawingPreview mGestureTrailsDrawingPreview;
138cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final SlidingKeyInputDrawingPreview mSlidingKeyInputDrawingPreview;
139375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
1400e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    // Key preview
141992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka    private final KeyPreviewDrawParams mKeyPreviewDrawParams;
142bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    private final KeyPreviewChoreographer mKeyPreviewChoreographer;
1430e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
1442affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka    // More keys keyboard
145f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    private final Paint mBackgroundDimAlphaPaint = new Paint();
146f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    private boolean mNeedsToDimEntireKeyboard;
147a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka    private final View mMoreKeysKeyboardContainer;
148a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka    private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = new WeakHashMap<>();
1492affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka    private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
150d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    // More keys panel (used by both more keys keyboard and more suggestions view)
151d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    // TODO: Consider extending to support multiple more keys panels
152d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    private MoreKeysPanel mMoreKeysPanel;
1535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
154375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    // Gesture floating preview text
155375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    // TODO: Make this parameter customizable by user via settings.
156375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private int mGestureFloatingPreviewTextLingerTimeout;
157375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
1582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final KeyDetector mKeyDetector;
159b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka    private final NonDistinctMultitouchHelper mNonDistinctMultitouchHelper;
1605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
1612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final TimerHandler mKeyTimerHandler;
162741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private final int mLanguageOnSpacebarHorizontalMargin;
1635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
164d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka    private final DrawingHandler mDrawingHandler = new DrawingHandler(this);
165375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
166d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka    private MainKeyboardAccessibilityDelegate mAccessibilityDelegate;
167bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka
168dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public MainKeyboardView(final Context context, final AttributeSet attrs) {
169c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        this(context, attrs, R.attr.mainKeyboardViewStyle);
1705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
1715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
172dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) {
1735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        super(context, attrs, defStyle);
1745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
175cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mDrawingPreviewPlacerView = new DrawingPreviewPlacerView(context, attrs);
1762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
1772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes(
1782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView);
1792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int ignoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt(
1802fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0);
1812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int gestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt(
1822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0);
1832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mKeyTimerHandler = new TimerHandler(
1842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                this, ignoreAltCodeKeyTimeout, gestureRecognitionUpdateTime);
1852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
1862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension(
1872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f);
1882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension(
1892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f);
1902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mKeyDetector = new KeyDetector(
1912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier);
1922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
193921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka        PointerTracker.init(mainKeyboardViewAttr, mKeyTimerHandler, this /* DrawingProxy */);
1942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
19513ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
19613ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final boolean forceNonDistinctMultitouch = prefs.getBoolean(
197a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka                DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false);
19813ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final boolean hasDistinctMultitouch = context.getPackageManager()
199b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)
200b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                && !forceNonDistinctMultitouch;
201b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        mNonDistinctMultitouchHelper = hasDistinctMultitouch ? null
202921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka                : new NonDistinctMultitouchHelper();
20322b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka
204f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        final int backgroundDimAlpha = mainKeyboardViewAttr.getInt(
205f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka                R.styleable.MainKeyboardView_backgroundDimAlpha, 0);
206f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        mBackgroundDimAlphaPaint.setColor(Color.BLACK);
207f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha);
2082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextRatio = mainKeyboardViewAttr.getFraction(
2092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f);
2102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextColor = mainKeyboardViewAttr.getColor(
2112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextColor, 0);
21241f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka        mLanguageOnSpacebarTextShadowRadius = mainKeyboardViewAttr.getFloat(
21341f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarTextShadowRadius,
21441f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka                LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED);
2152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextShadowColor = mainKeyboardViewAttr.getColor(
2162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextShadowColor, 0);
217d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt(
218c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha,
2194daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang                Constants.Color.ALPHA_OPAQUE);
220d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int languageOnSpacebarFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId(
221c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0);
222d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int altCodeKeyWhileTypingFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId(
223c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0);
224d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int altCodeKeyWhileTypingFadeinAnimatorResId = mainKeyboardViewAttr.getResourceId(
225c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0);
226160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka
227992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka        mKeyPreviewDrawParams = new KeyPreviewDrawParams(mainKeyboardViewAttr);
228bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer = new KeyPreviewChoreographer(mKeyPreviewDrawParams);
229bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
230a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId(
231d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka                R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0);
232d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean(
233c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false);
234375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
235375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mGestureFloatingPreviewTextLingerTimeout = mainKeyboardViewAttr.getInt(
236375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka                R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0);
237fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
238cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview = new GestureFloatingTextDrawingPreview(
2397fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka                mainKeyboardViewAttr);
2407fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.setDrawingView(mDrawingPreviewPlacerView);
241fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
2427fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mGestureTrailsDrawingPreview = new GestureTrailsDrawingPreview(mainKeyboardViewAttr);
2437fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setDrawingView(mDrawingPreviewPlacerView);
244fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
2457fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview = new SlidingKeyInputDrawingPreview(mainKeyboardViewAttr);
2467fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.setDrawingView(mDrawingPreviewPlacerView);
247d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mainKeyboardViewAttr.recycle();
248160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka
249a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        mMoreKeysKeyboardContainer = LayoutInflater.from(getContext())
250a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka                .inflate(moreKeysKeyboardLayoutId, null);
25131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator(
25231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                languageOnSpacebarFadeoutAnimatorResId, this);
25331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator(
25431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                altCodeKeyWhileTypingFadeoutAnimatorResId, this);
25531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator(
25631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                altCodeKeyWhileTypingFadeinAnimatorResId, this);
257f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka
258f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka        mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
259741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka
2602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarHorizontalMargin = (int)getResources().getDimension(
2612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.dimen.config_language_on_spacebar_horizontal_margin);
26231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
26331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
26452876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    @Override
26552876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
26652876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa        super.setHardwareAcceleratedDrawingEnabled(enabled);
267cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mDrawingPreviewPlacerView.setHardwareAcceleratedDrawingEnabled(enabled);
26852876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    }
26952876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa
270dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    private ObjectAnimator loadObjectAnimator(final int resId, final Object target) {
27120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (resId == 0) {
27257372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka            // TODO: Stop returning null.
27320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return null;
27420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
27531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator(
27631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                getContext(), resId);
277d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka        if (animator != null) {
27831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka            animator.setTarget(target);
27973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka        }
28031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return animator;
28131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
28273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka
2832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel,
2842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            final ObjectAnimator animatorToStart) {
2852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (animatorToCancel == null || animatorToStart == null) {
2862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            // TODO: Stop using null as a no-operation animator.
2872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return;
2882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
2892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        float startFraction = 0.0f;
2902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (animatorToCancel.isStarted()) {
2912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            animatorToCancel.cancel();
2922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            startFraction = 1.0f - animatorToCancel.getAnimatedFraction();
2932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
2942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final long startTime = (long)(animatorToStart.getDuration() * startFraction);
2952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        animatorToStart.start();
2962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        animatorToStart.setCurrentPlayTime(startTime);
2972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
2982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
2992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link TimerHander.Callbacks} method.
3002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
3012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void startWhileTypingFadeinAnimation() {
3022fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        cancelAndStartAnimators(
3032fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                mAltCodeKeyWhileTypingFadeoutAnimator, mAltCodeKeyWhileTypingFadeinAnimator);
3042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
3052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
3062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
3072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void startWhileTypingFadeoutAnimation() {
3082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        cancelAndStartAnimators(
3092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                mAltCodeKeyWhileTypingFadeinAnimator, mAltCodeKeyWhileTypingFadeoutAnimator);
3102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
3112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
31215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
31331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    public int getLanguageOnSpacebarAnimAlpha() {
31431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return mLanguageOnSpacebarAnimAlpha;
315d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka    }
316d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka
31715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
318dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setLanguageOnSpacebarAnimAlpha(final int alpha) {
31931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mLanguageOnSpacebarAnimAlpha = alpha;
32031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        invalidateKey(mSpaceKey);
32131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
32231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
32315f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
32431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    public int getAltCodeKeyWhileTypingAnimAlpha() {
32531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return mAltCodeKeyWhileTypingAnimAlpha;
32631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
32731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
32815f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
329dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) {
3305141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        if (mAltCodeKeyWhileTypingAnimAlpha == alpha) {
3315141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            return;
3325141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3335141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        // Update the visual of alt-code-key-while-typing.
33431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingAnimAlpha = alpha;
3355141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        final Keyboard keyboard = getKeyboard();
3365141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        if (keyboard == null) {
3375141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            return;
3385141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3395141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        for (final Key key : keyboard.mAltCodeKeysWhileTyping) {
3405141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            invalidateKey(key);
3415141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
344dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setKeyboardActionListener(final KeyboardActionListener listener) {
3455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        mKeyboardActionListener = listener;
3465c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka        PointerTracker.setKeyboardActionListener(listener);
3475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
3492fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // TODO: We should reconsider which coordinate system should be used to represent keyboard
3502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // event.
3512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public int getKeyX(final int x) {
3522fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return Constants.isValidCoordinate(x) ? mKeyDetector.getTouchX(x) : x;
3535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
3552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // TODO: We should reconsider which coordinate system should be used to represent keyboard
3562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // event.
3572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public int getKeyY(final int y) {
3582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return Constants.isValidCoordinate(y) ? mKeyDetector.getTouchY(y) : y;
3590efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka    }
3600efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka
3615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    /**
3625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * Attaches a keyboard to this view. The keyboard can be switched at any time and the
3635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * view will re-layout itself to accommodate the keyboard.
3645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @see Keyboard
3655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @see #getKeyboard()
3665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @param keyboard the keyboard to display in this view
3675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     */
3685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
369dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setKeyboard(final Keyboard keyboard) {
3705cbda70956af14453fca7395d892c59aabbd8fd3Jean Chalard        // Remove any pending messages, except dismissing preview and key repeat.
3715cbda70956af14453fca7395d892c59aabbd8fd3Jean Chalard        mKeyTimerHandler.cancelLongPressTimers();
3725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        super.setKeyboard(keyboard);
3735a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka        mKeyDetector.setKeyboard(
37408ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
3758335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        PointerTracker.setKeyDetector(mKeyDetector);
376a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        mMoreKeysKeyboardCache.clear();
3774112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
378240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka        mSpaceKey = keyboard.getKey(Constants.CODE_SPACE);
3794112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
3802fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextSize = keyHeight * mLanguageOnSpacebarTextRatio;
381f147794fd41491a3383e6aca6d49007f58124068alanv
382d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
383dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka            if (mAccessibilityDelegate == null) {
384dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka                mAccessibilityDelegate = new MainKeyboardAccessibilityDelegate(this, mKeyDetector);
385dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka            }
386ae0fab9550f1d9159d819dbb0b7cc86c2bf2937cTadashi G. Takaoka            mAccessibilityDelegate.setKeyboard(keyboard);
387d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        } else {
388ae0fab9550f1d9159d819dbb0b7cc86c2bf2937cTadashi G. Takaoka            mAccessibilityDelegate = null;
389d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        }
3905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
3920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    /**
3930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * Enables or disables the key feedback popup. This is a popup that shows a magnified
3940e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * version of the depressed key. By default the preview is enabled.
3950e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * @param previewEnabled whether or not to enable the key feedback preview
3960e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * @param delay the delay after which the preview is dismissed
3970e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * @see #isKeyPreviewPopupEnabled()
3980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     */
3990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) {
4007d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka        mKeyPreviewDrawParams.setPopupEnabled(previewEnabled, delay);
4010e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
4020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
403276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka    public void setKeyPreviewAnimationParams(final float showUpStartScale, final int showUpDuration,
404276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka            final float dismissEndScale, final int dismissDuration) {
405276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka        mKeyPreviewDrawParams.setAnimationParams(
406276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka                showUpStartScale, showUpDuration, dismissEndScale, dismissDuration);
407276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka    }
408276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka
409375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private void locatePreviewPlacerView() {
410375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        getLocationInWindow(mOriginCoords);
4110c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        mDrawingPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, getWidth(), getHeight());
4120c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka    }
4130c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka
4140c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka    private void installPreviewPlacerView() {
415375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        final View rootView = getRootView();
416375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        if (rootView == null) {
417375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka            Log.w(TAG, "Cannot find root view");
418375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka            return;
419375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        }
420375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content);
421375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        // Note: It'd be very weird if we get null by android.R.id.content.
422375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        if (windowContentView == null) {
423cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka            Log.w(TAG, "Cannot find android.R.id.content view to add DrawingPreviewPlacerView");
4240c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka            return;
425375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        }
4260c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        windowContentView.addView(mDrawingPreviewPlacerView);
427375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
428375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
4292fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link DrawingHandler.Callbacks} method.
4302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
4312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void dismissAllKeyPreviews() {
432bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer.dismissAllKeyPreviews();
433375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        PointerTracker.setReleasedKeyGraphicsToAllKeys();
434375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
435375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
4360e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
4372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void showKeyPreview(final Key key) {
438a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        // If the key is invalid or has no key preview, we must not show key preview.
439a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        if (key == null || key.noKeyPreview()) {
4400e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka            return;
4410e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        }
4422fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final Keyboard keyboard = getKeyboard();
443a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        if (keyboard == null) {
444a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka            return;
445a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        }
446a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams;
4477d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka        if (!previewParams.isPopupEnabled()) {
448992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka            previewParams.setVisibleOffset(-keyboard.mVerticalGap);
4492fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return;
4502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
4512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
452bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        locatePreviewPlacerView();
4530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        getLocationInWindow(mOriginCoords);
45484405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka        mKeyPreviewChoreographer.placeAndShowKeyPreview(key, keyboard.mIconsSet, mKeyDrawParams,
4553ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka                getWidth(), mOriginCoords, mDrawingPreviewPlacerView, isHardwareAccelerated());
4562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
4572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
4582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link TimerHandler.Callbacks} method.
4590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
4602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void dismissKeyPreviewWithoutDelay(final Key key) {
461bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer.dismissKeyPreview(key, false /* withAnimation */);
4622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // To redraw key top letter.
4632fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        invalidateKey(key);
4642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
4652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
4662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
4672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void dismissKeyPreview(final Key key) {
4682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (!isHardwareAccelerated()) {
4692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            // TODO: Implement preference option to control key preview method and duration.
4707d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka            mDrawingHandler.dismissKeyPreview(mKeyPreviewDrawParams.getLingerTimeout(), key);
4712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return;
4722fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
473bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer.dismissKeyPreview(key, true /* withAnimation */);
4740e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
4750e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
476ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka    public void setSlidingKeyInputPreviewEnabled(final boolean enabled) {
477cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.setPreviewEnabled(enabled);
478ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka    }
479ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka
4800e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
4810e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    public void showSlidingKeyInputPreview(final PointerTracker tracker) {
4820e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        locatePreviewPlacerView();
483cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.setPreviewPosition(tracker);
4840e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
4850e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
4860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
4870e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    public void dismissSlidingKeyInputPreview() {
488cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.dismissSlidingKeyInputPreview();
4890e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
4900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
491724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa    private void setGesturePreviewMode(final boolean isGestureTrailEnabled,
492724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureFloatingPreviewTextEnabled) {
493cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.setPreviewEnabled(isGestureFloatingPreviewTextEnabled);
494cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setPreviewEnabled(isGestureTrailEnabled);
495375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
496375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
4972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link DrawingHandler.Callbacks} method.
4982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
499375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) {
500375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        locatePreviewPlacerView();
501cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.setSuggetedWords(suggestedWords);
502375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
503375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
504375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    public void dismissGestureFloatingPreviewText() {
505375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        locatePreviewPlacerView();
506375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mDrawingHandler.dismissGestureFloatingPreviewText(mGestureFloatingPreviewTextLingerTimeout);
507375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
508375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
509fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka    @Override
510212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka    public void showGestureTrail(final PointerTracker tracker,
511212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka            final boolean showsFloatingPreviewText) {
512375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        locatePreviewPlacerView();
513212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka        if (showsFloatingPreviewText) {
514cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka            mGestureFloatingTextDrawingPreview.setPreviewPosition(tracker);
515212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka        }
516cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setPreviewPosition(tracker);
517375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
518375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
5198335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka    // Note that this method is called from a non-UI thread.
520c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka    @SuppressWarnings("static-method")
521dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) {
5228335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable);
5238335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka    }
5248335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka
525724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa    public void setGestureHandlingEnabledByUser(final boolean isGestureHandlingEnabledByUser,
526724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureTrailEnabled,
527724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureFloatingPreviewTextEnabled) {
528724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa        PointerTracker.setGestureHandlingEnabledByUser(isGestureHandlingEnabledByUser);
529724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa        setGesturePreviewMode(isGestureHandlingEnabledByUser && isGestureTrailEnabled,
530724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa                isGestureHandlingEnabledByUser && isGestureFloatingPreviewTextEnabled);
5310657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka    }
5320657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka
5335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
5344331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    protected void onAttachedToWindow() {
5354331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        super.onAttachedToWindow();
5360c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        installPreviewPlacerView();
537c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    }
538c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka
539c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    @Override
540c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    protected void onDetachedFromWindow() {
541c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka        super.onDetachedFromWindow();
542cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mDrawingPreviewPlacerView.removeAllViews();
5434331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
5444331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
545a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka    private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) {
54603288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        final MoreKeySpec[] moreKeys = key.getMoreKeys();
54703288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        if (moreKeys == null) {
5485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka            return null;
54920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
550a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key);
551a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (moreKeysKeyboard == null) {
55203288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link KeyPreviewDrawParams#mPreviewVisibleWidth} should have been set at
55303288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link KeyPreviewChoreographer#placeKeyPreview(Key,TextView,KeyboardIconsSet,KeyDrawParams,int,int[]},
55403288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // though there may be some chances that the value is zero. <code>width == 0</code>
55503288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // will cause zero-division error at
55603288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link MoreKeysKeyboardParams#setParameters(int,int,int,int,int,int,boolean,int)}.
55784405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka            final boolean isSingleMoreKeyWithPreview = mKeyPreviewDrawParams.isPopupEnabled()
55803288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    && !key.noKeyPreview() && moreKeys.length == 1
55903288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    && mKeyPreviewDrawParams.getVisibleWidth() > 0;
56003288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            final MoreKeysKeyboard.Builder builder = new MoreKeysKeyboard.Builder(
56184405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka                    context, key, getKeyboard(), isSingleMoreKeyWithPreview,
56203288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    mKeyPreviewDrawParams.getVisibleWidth(),
56303288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    mKeyPreviewDrawParams.getVisibleHeight(), newLabelPaint(key));
56403288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            moreKeysKeyboard = builder.build();
565a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka            mMoreKeysKeyboardCache.put(key, moreKeysKeyboard);
56620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
5675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
568a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        final View container = mMoreKeysKeyboardContainer;
5692affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        final MoreKeysKeyboardView moreKeysKeyboardView =
5702affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka                (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view);
5712affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        moreKeysKeyboardView.setKeyboard(moreKeysKeyboard);
572b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka        container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
5732affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        return moreKeysKeyboardView;
5745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
5755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
5762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link TimerHandler.Callbacks} method.
5775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    /**
578d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka     * Called when a key is long pressed.
5795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @param tracker the pointer tracker which pressed the parent key
5805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     */
5812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
5822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void onLongPress(final PointerTracker tracker) {
583a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (isShowingMoreKeysPanel()) {
58496efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka            return;
585a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        }
586a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        final Key key = tracker.getKey();
587a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (key == null) {
58896efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka            return;
589a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        }
590f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka        final KeyboardActionListener listener = mKeyboardActionListener;
5919552badf3c24d2098d227b0ddca0721b928a10b1Tadashi G. Takaoka        if (key.hasNoPanelAutoMoreKey()) {
5927dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka            final int moreKeyCode = key.getMoreKeys()[0].mCode;
5933708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka            tracker.onLongPressed();
594ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            listener.onPressKey(moreKeyCode, 0 /* repeatCount */, true /* isSinglePointer */);
5952282e8520a2c1984989a14fb09896536f5033b26Jean Chalard            listener.onCodeInput(moreKeyCode, Constants.NOT_A_COORDINATE,
5962282e8520a2c1984989a14fb09896536f5033b26Jean Chalard                    Constants.NOT_A_COORDINATE, false /* isKeyRepeat */);
597f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka            listener.onReleaseKey(moreKeyCode, false /* withSliding */);
59896efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka            return;
5993708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka        }
6007dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int code = key.getCode();
601a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) {
6023708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka            // Long pressing the space key invokes IME switcher dialog.
603f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka            if (listener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) {
6046dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka                tracker.onLongPressed();
605f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka                listener.onReleaseKey(code, false /* withSliding */);
60696efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka                return;
6076dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka            }
6086dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka        }
60996efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka        openMoreKeysPanel(key, tracker);
6106dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka    }
6116dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka
61296efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka    private void openMoreKeysPanel(final Key key, final PointerTracker tracker) {
613a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        final MoreKeysPanel moreKeysPanel = onCreateMoreKeysPanel(key, getContext());
6149d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka        if (moreKeysPanel == null) {
61596efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka            return;
6165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        }
61763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka
618547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka        final int[] lastCoords = CoordinateUtils.newInstance();
619547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka        tracker.getLastCoordinates(lastCoords);
62003288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        final boolean keyPreviewEnabled = mKeyPreviewDrawParams.isPopupEnabled()
62103288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                && !key.noKeyPreview();
6227ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // The more keys keyboard is usually horizontally aligned with the center of the parent key.
6237ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more
6247ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // keys keyboard is placed at the touch point of the parent key.
6257ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled)
626547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka                ? CoordinateUtils.x(lastCoords)
6277dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka                : key.getX() + key.getWidth() / 2;
6287ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // The more keys keyboard is usually vertically aligned with the top edge of the parent key
6297ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically
6307ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // aligned with the bottom edge of the visible part of the key preview.
63129d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka        // {@code mPreviewVisibleOffset} has been set appropriately in
63229d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka        // {@link KeyboardView#showKeyPreview(PointerTracker)}.
633992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka        final int pointY = key.getY() + mKeyPreviewDrawParams.getVisibleOffset();
634fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener);
63533482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka        tracker.onShowMoreKeysPanel(moreKeysPanel);
6362fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // TODO: Implement zoom in animation of more keys panel.
6372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        dismissKeyPreviewWithoutDelay(key);
6385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
6395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
6402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public boolean isInDraggingFinger() {
641a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (isShowingMoreKeysPanel()) {
64263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka            return true;
6435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        }
6442fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return PointerTracker.isAnyInDraggingFinger();
6455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
6465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
647d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
648d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    public void onShowMoreKeysPanel(final MoreKeysPanel panel) {
6491b6eea89037158a1e271730eacdacb8b6e550d3aTadashi G. Takaoka        locatePreviewPlacerView();
650cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        panel.showInParent(mDrawingPreviewPlacerView);
651d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mMoreKeysPanel = panel;
652a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        dimEntireKeyboard(true /* dimmed */);
653d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
654d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
655d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    public boolean isShowingMoreKeysPanel() {
656a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        return mMoreKeysPanel != null && mMoreKeysPanel.isShowingInParent();
657d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
658d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
659d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
6601f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka    public void onCancelMoreKeysPanel() {
661d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        PointerTracker.dismissAllMoreKeysPanels();
662d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
663d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
664d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
6651f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka    public void onDismissMoreKeysPanel() {
666d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        dimEntireKeyboard(false /* dimmed */);
667d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        if (isShowingMoreKeysPanel()) {
6687f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka            mMoreKeysPanel.removeFromParent();
669d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka            mMoreKeysPanel = null;
670d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        }
671d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
672d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
6735433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public void startDoubleTapShiftKeyTimer() {
6745433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka        mKeyTimerHandler.startDoubleTapShiftKeyTimer();
6755433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
6765433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
6775433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public void cancelDoubleTapShiftKeyTimer() {
6785433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka        mKeyTimerHandler.cancelDoubleTapShiftKeyTimer();
6795433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
6805433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
6815433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public boolean isInDoubleTapShiftKeyTimeout() {
6825433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka        return mKeyTimerHandler.isInDoubleTapShiftKeyTimeout();
6835433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
6845433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
6855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
686dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public boolean onTouchEvent(final MotionEvent me) {
68746286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka        if (getKeyboard() == null) {
68846286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka            return false;
68946286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka        }
690b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        if (mNonDistinctMultitouchHelper != null) {
691b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            if (me.getPointerCount() > 1 && mKeyTimerHandler.isInKeyRepeat()) {
692b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                // Key repeating timer will be canceled if 2 or more keys are in action.
6932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                mKeyTimerHandler.cancelKeyRepeatTimers();
694b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            }
695b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            // Non distinct multitouch screen support
6962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            mNonDistinctMultitouchHelper.processMotionEvent(me, mKeyDetector);
697b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            return true;
698b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        }
699310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka        return processMotionEvent(me);
700c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka    }
701c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka
702dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public boolean processMotionEvent(final MotionEvent me) {
703e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka        final int index = me.getActionIndex();
704e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka        final int id = me.getPointerId(index);
7052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final PointerTracker tracker = PointerTracker.getPointerTracker(id);
7062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // When a more keys panel is showing, we should ignore other fingers' single touch events
7072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // other than the finger that is showing the more keys panel.
7082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (isShowingMoreKeysPanel() && !tracker.isShowingMoreKeysPanel()
7092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                && PointerTracker.getActivePointerTrackerCount() == 1) {
7102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return true;
7112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
7122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        tracker.processMotionEvent(me, mKeyDetector);
7135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        return true;
7145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
7155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
7165c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka    public void cancelAllOngoingEvents() {
717375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mKeyTimerHandler.cancelAllMessages();
718375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mDrawingHandler.cancelAllMessages();
7195c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        dismissAllKeyPreviews();
7205c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        dismissGestureFloatingPreviewText();
7215c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        dismissSlidingKeyInputPreview();
7225c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        PointerTracker.dismissAllMoreKeysPanels();
7235c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        PointerTracker.cancelAllPointerTrackers();
724375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
725375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
7265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    public void closing() {
7275c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        cancelAllOngoingEvents();
728a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        mMoreKeysKeyboardCache.clear();
7295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
7305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
731bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka    public void onHideWindow() {
732a74719c934ceb30d2afb7ae999c909f5c6fd5325Tadashi G. Takaoka        onDismissMoreKeysPanel();
733d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
734d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        if (accessibilityDelegate != null) {
735d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka            accessibilityDelegate.onHideWindow();
7361ead609e6fd64fd5ac2979ac3802d8bada7d7f49Tadashi G. Takaoka        }
737bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka    }
738bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka
739586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette    /**
7409647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka     * {@inheritDoc}
741586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette     */
742c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka    @Override
7439647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka    public boolean onHoverEvent(final MotionEvent event) {
744d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
745d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        if (accessibilityDelegate != null) {
746d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka            return accessibilityDelegate.onHoverEvent(event);
7475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        }
7489647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka        return super.onHoverEvent(event);
7495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
75022b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka
751dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void updateShortcutKey(final boolean available) {
7527bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        final Keyboard keyboard = getKeyboard();
75320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (keyboard == null) {
75420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return;
75520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
756240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka        final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT);
75720dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (shortcutKey == null) {
75820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return;
75920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
7607bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        shortcutKey.setEnabled(available);
7617bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        invalidateKey(shortcutKey);
7625afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka    }
7635afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka
764dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged,
7657dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            final int languageOnSpacebarFormatType,
7667dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            final boolean hasMultipleEnabledIMEsOrSubtypes) {
7677dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka        mLanguageOnSpacebarFormatType = languageOnSpacebarFormatType;
768fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka        mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes;
769fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka        final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator;
770d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka        if (animator == null) {
7717dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            mLanguageOnSpacebarFormatType = LanguageOnSpacebarHelper.FORMAT_TYPE_NONE;
7724c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka        } else {
7737dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            if (subtypeChanged
7747dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka                    && languageOnSpacebarFormatType != LanguageOnSpacebarHelper.FORMAT_TYPE_NONE) {
7754daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang                setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE);
77631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                if (animator.isStarted()) {
77731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                    animator.cancel();
77831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                }
779d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka                animator.start();
780dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka            } else {
78131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                if (!animator.isStarted()) {
78231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                    mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha;
78331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                }
784dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka            }
7854c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka        }
7864112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        invalidateKey(mSpaceKey);
7874112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    }
7884112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
789a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka    private void dimEntireKeyboard(final boolean dimmed) {
790f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        final boolean needsRedrawing = mNeedsToDimEntireKeyboard != dimmed;
791f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        mNeedsToDimEntireKeyboard = dimmed;
792f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        if (needsRedrawing) {
793f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka            invalidateAllKeys();
794f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        }
795f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    }
796f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka
797f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    @Override
798f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    protected void onDraw(final Canvas canvas) {
799f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        super.onDraw(canvas);
800f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka
801f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        // Overlay a dark rectangle to dim.
802f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        if (mNeedsToDimEntireKeyboard) {
80308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka            canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mBackgroundDimAlphaPaint);
804f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        }
805f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    }
806f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka
80722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka    @Override
808dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint,
809dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka            final KeyDrawParams params) {
8106bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka        if (key.altCodeWhileTyping() && key.isEnabled()) {
81173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka            params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha;
81273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka        }
81341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        super.onDrawKeyTopVisuals(key, canvas, paint, params);
8147dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int code = key.getCode();
8157dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        if (code == Constants.CODE_SPACE) {
81641808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            // If input language are explicitly selected.
81741808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            if (mLanguageOnSpacebarFormatType != LanguageOnSpacebarHelper.FORMAT_TYPE_NONE) {
81841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka                drawLanguageOnSpacebar(key, canvas, paint);
81941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            }
8204112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka            // Whether space key needs to show the "..." popup hint for special purposes
821fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka            if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) {
822bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka                drawKeyPopupHint(key, canvas, paint, params);
8234112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka            }
8247dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        } else if (code == Constants.CODE_LANGUAGE_SWITCH) {
825fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka            drawKeyPopupHint(key, canvas, paint, params);
82622b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka        }
82722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka    }
8284112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
829741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private boolean fitsTextIntoWidth(final int width, final String text, final Paint paint) {
830741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka        final int maxTextWidth = width - mLanguageOnSpacebarHorizontalMargin * 2;
831bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        paint.setTextScaleX(1.0f);
8322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float textWidth = TypefaceUtils.getStringWidth(text, paint);
83320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (textWidth < width) {
83420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return true;
83520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
836bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
837741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka        final float scaleX = maxTextWidth / textWidth;
83820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) {
83920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return false;
84020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
841bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
842bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        paint.setTextScaleX(scaleX);
8432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return TypefaceUtils.getStringWidth(text, paint) < maxTextWidth;
844bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    }
845bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
846bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    // Layout language name on spacebar.
847741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private String layoutLanguageOnSpacebar(final Paint paint,
84808ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka            final InputMethodSubtype subtype, final int width) {
849bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        // Choose appropriate language name to fit into the width.
8507dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka        if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_FULL_LOCALE) {
8517dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            final String fullText = SpacebarLanguageUtils.getFullDisplayName(subtype);
8527dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            if (fitsTextIntoWidth(width, fullText, paint)) {
8537dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka                return fullText;
8547dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            }
855bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        }
856bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
8579364d46ac3590d23b8117a66efc8756454cef772Tadashi G. Takaoka        final String middleText = SpacebarLanguageUtils.getMiddleDisplayName(subtype);
85820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (fitsTextIntoWidth(width, middleText, paint)) {
85920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return middleText;
8604112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        }
8614112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
862bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        return "";
8634112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    }
8644112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
86541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka    private void drawLanguageOnSpacebar(final Key key, final Canvas canvas, final Paint paint) {
8667dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int width = key.getWidth();
8677dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int height = key.getHeight();
86841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTextAlign(Align.CENTER);
86941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTypeface(Typeface.DEFAULT);
87041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTextSize(mLanguageOnSpacebarTextSize);
87141808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final InputMethodSubtype subtype = getKeyboard().mId.mSubtype;
87241808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final String language = layoutLanguageOnSpacebar(paint, subtype, 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