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;
49016d6c424cf004c282db5a57e64f3d1eee672a22Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyPreviewView;
507dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper;
5103288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.MoreKeySpec;
52b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper;
53cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview;
542fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport com.android.inputmethod.keyboard.internal.TimerHandler;
554daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyangimport com.android.inputmethod.latin.Constants;
565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
57375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords;
58a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.DebugSettings;
59e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CoordinateUtils;
609364d46ac3590d23b8117a66efc8756454cef772Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.SpacebarLanguageUtils;
61ccf4a310279b13bbf0b6aac76a0878178c1dfb7dTadashi G. Takaokaimport com.android.inputmethod.latin.utils.TypefaceUtils;
625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap;
645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/**
665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements.
675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka *
682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextRatio
692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextColor
7041f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowRadius
712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowColor
72dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha
73dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFadeoutAnimator
74dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator
75dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator
76dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyHysteresisDistance
77dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdTime
78dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_touchNoiseThresholdDistance
792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @attr ref R.styleable#MainKeyboardView_keySelectionByDraggingFinger
80dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatStartTimeout
81dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyRepeatInterval
82dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressKeyTimeout
83dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_longPressShiftKeyTimeout
84dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_ignoreAltCodeKeyTimeout
85375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLayout
860e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewOffset
870e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewHeight
880e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewLingerTimeout
89ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewShowUpAnimator
90ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_keyPreviewDismissAnimator
91d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardLayout
920f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardForActionLayout
93f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_backgroundDimAlpha
94dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint
95375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureFloatingPreviewTextLingerTimeout
963623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureStaticTimeThresholdAfterFastTyping
973623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDetectFastMoveSpeedThreshold
983623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicThresholdDecayDuration
993623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdFrom
1003623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicTimeThresholdTo
1013623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdFrom
1023623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureDynamicDistanceThresholdTo
1033623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureSamplingMinimumDistance
1043623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionMinimumTime
1053623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_gestureRecognitionSpeedThreshold
1063623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka * @attr ref R.styleable#MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration
1075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */
1082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasapublic final class MainKeyboardView extends KeyboardView implements PointerTracker.DrawingProxy,
1092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        MoreKeysPanel.Controller, DrawingHandler.Callbacks, TimerHandler.Callbacks {
110c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String TAG = MainKeyboardView.class.getSimpleName();
1115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
112bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    /** Listener for {@link KeyboardActionListener}. */
113bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    private KeyboardActionListener mKeyboardActionListener;
114bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka
1152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    /* Space key and its icon and background. */
1164112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    private Key mSpaceKey;
117bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka    // Stuff to draw language name on spacebar.
11831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    private final int mLanguageOnSpacebarFinalAlpha;
11931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator;
1207dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka    private int mLanguageOnSpacebarFormatType;
121fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka    private boolean mHasMultipleEnabledIMEsOrSubtypes;
1224daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang    private int mLanguageOnSpacebarAnimAlpha = Constants.Color.ALPHA_OPAQUE;
1232fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final float mLanguageOnSpacebarTextRatio;
1242fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private float mLanguageOnSpacebarTextSize;
1252fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final int mLanguageOnSpacebarTextColor;
12641f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka    private final float mLanguageOnSpacebarTextShadowRadius;
1272fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final int mLanguageOnSpacebarTextShadowColor;
12841f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka    private static final float LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
129bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    // The minimum x-scale to fit the language name on spacebar.
130bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f;
13115d4793911fa305e0a58aced925961e948582979satok
13273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka    // Stuff to draw altCodeWhileTyping keys.
1332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final ObjectAnimator mAltCodeKeyWhileTypingFadeoutAnimator;
1342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final ObjectAnimator mAltCodeKeyWhileTypingFadeinAnimator;
1354daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang    private int mAltCodeKeyWhileTypingAnimAlpha = Constants.Color.ALPHA_OPAQUE;
13673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka
137cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    // Drawing preview placer view
138cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final DrawingPreviewPlacerView mDrawingPreviewPlacerView;
139375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private final int[] mOriginCoords = CoordinateUtils.newInstance();
140cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final GestureFloatingTextDrawingPreview mGestureFloatingTextDrawingPreview;
141cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final GestureTrailsDrawingPreview mGestureTrailsDrawingPreview;
142cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka    private final SlidingKeyInputDrawingPreview mSlidingKeyInputDrawingPreview;
143375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
1440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    // Key preview
145992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka    private final KeyPreviewDrawParams mKeyPreviewDrawParams;
146bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka    private final KeyPreviewChoreographer mKeyPreviewChoreographer;
1470e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
1482affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka    // More keys keyboard
149f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    private final Paint mBackgroundDimAlphaPaint = new Paint();
150f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    private boolean mNeedsToDimEntireKeyboard;
151a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka    private final View mMoreKeysKeyboardContainer;
1520f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka    private final View mMoreKeysKeyboardForActionContainer;
153a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka    private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = new WeakHashMap<>();
1542affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka    private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
155d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    // More keys panel (used by both more keys keyboard and more suggestions view)
156d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    // TODO: Consider extending to support multiple more keys panels
157d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    private MoreKeysPanel mMoreKeysPanel;
1585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
159375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    // Gesture floating preview text
160375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    // TODO: Make this parameter customizable by user via settings.
161375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private int mGestureFloatingPreviewTextLingerTimeout;
162375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
1632fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final KeyDetector mKeyDetector;
164b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka    private final NonDistinctMultitouchHelper mNonDistinctMultitouchHelper;
1655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
1662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private final TimerHandler mKeyTimerHandler;
167741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private final int mLanguageOnSpacebarHorizontalMargin;
1685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
169d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka    private final DrawingHandler mDrawingHandler = new DrawingHandler(this);
170375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
171d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka    private MainKeyboardAccessibilityDelegate mAccessibilityDelegate;
172bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka
173dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public MainKeyboardView(final Context context, final AttributeSet attrs) {
174c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        this(context, attrs, R.attr.mainKeyboardViewStyle);
1755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
1765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
177dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) {
1785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        super(context, attrs, defStyle);
1795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
180cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mDrawingPreviewPlacerView = new DrawingPreviewPlacerView(context, attrs);
1812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
1822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes(
1832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                attrs, R.styleable.MainKeyboardView, defStyle, R.style.MainKeyboardView);
1842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int ignoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt(
1852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0);
1862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final int gestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt(
1872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_gestureRecognitionUpdateTime, 0);
1882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mKeyTimerHandler = new TimerHandler(
1892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                this, ignoreAltCodeKeyTimeout, gestureRecognitionUpdateTime);
1902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
1912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float keyHysteresisDistance = mainKeyboardViewAttr.getDimension(
1922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_keyHysteresisDistance, 0.0f);
1932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float keyHysteresisDistanceForSlidingModifier = mainKeyboardViewAttr.getDimension(
1942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_keyHysteresisDistanceForSlidingModifier, 0.0f);
1952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mKeyDetector = new KeyDetector(
1962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                keyHysteresisDistance, keyHysteresisDistanceForSlidingModifier);
1972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
198921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka        PointerTracker.init(mainKeyboardViewAttr, mKeyTimerHandler, this /* DrawingProxy */);
1992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
20013ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
20113ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final boolean forceNonDistinctMultitouch = prefs.getBoolean(
202a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka                DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false);
20313ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka        final boolean hasDistinctMultitouch = context.getPackageManager()
204b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)
205b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                && !forceNonDistinctMultitouch;
206b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        mNonDistinctMultitouchHelper = hasDistinctMultitouch ? null
207921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka                : new NonDistinctMultitouchHelper();
20822b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka
209f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        final int backgroundDimAlpha = mainKeyboardViewAttr.getInt(
210f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka                R.styleable.MainKeyboardView_backgroundDimAlpha, 0);
211f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        mBackgroundDimAlphaPaint.setColor(Color.BLACK);
212f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha);
2132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextRatio = mainKeyboardViewAttr.getFraction(
2142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f);
2152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextColor = mainKeyboardViewAttr.getColor(
2162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextColor, 0);
21741f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka        mLanguageOnSpacebarTextShadowRadius = mainKeyboardViewAttr.getFloat(
21841f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarTextShadowRadius,
21941f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka                LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED);
2202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextShadowColor = mainKeyboardViewAttr.getColor(
2212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.styleable.MainKeyboardView_languageOnSpacebarTextShadowColor, 0);
222d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt(
223c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarFinalAlpha,
2244daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang                Constants.Color.ALPHA_OPAQUE);
225d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int languageOnSpacebarFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId(
226c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_languageOnSpacebarFadeoutAnimator, 0);
227d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int altCodeKeyWhileTypingFadeoutAnimatorResId = mainKeyboardViewAttr.getResourceId(
228c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator, 0);
229d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        final int altCodeKeyWhileTypingFadeinAnimatorResId = mainKeyboardViewAttr.getResourceId(
230c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_altCodeKeyWhileTypingFadeinAnimator, 0);
231160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka
232992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka        mKeyPreviewDrawParams = new KeyPreviewDrawParams(mainKeyboardViewAttr);
233bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer = new KeyPreviewChoreographer(mKeyPreviewDrawParams);
234bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka
235a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId(
236d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka                R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0);
2370f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        final int moreKeysKeyboardForActionLayoutId = mainKeyboardViewAttr.getResourceId(
2380f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka                R.styleable.MainKeyboardView_moreKeysKeyboardForActionLayout,
2390f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka                moreKeysKeyboardLayoutId);
240d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean(
241c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false);
242375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
243375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mGestureFloatingPreviewTextLingerTimeout = mainKeyboardViewAttr.getInt(
244375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka                R.styleable.MainKeyboardView_gestureFloatingPreviewTextLingerTimeout, 0);
245fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
246cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview = new GestureFloatingTextDrawingPreview(
2477fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka                mainKeyboardViewAttr);
2487fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.setDrawingView(mDrawingPreviewPlacerView);
249fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
2507fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mGestureTrailsDrawingPreview = new GestureTrailsDrawingPreview(mainKeyboardViewAttr);
2517fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setDrawingView(mDrawingPreviewPlacerView);
252fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka
2537fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview = new SlidingKeyInputDrawingPreview(mainKeyboardViewAttr);
2547fb630b2a83983ea42108969b82ca85886e19241Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.setDrawingView(mDrawingPreviewPlacerView);
255d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mainKeyboardViewAttr.recycle();
256160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka
2570f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(getContext());
2580f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        mMoreKeysKeyboardContainer = inflater.inflate(moreKeysKeyboardLayoutId, null);
2590f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        mMoreKeysKeyboardForActionContainer = inflater.inflate(
2600f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka                moreKeysKeyboardForActionLayoutId, null);
26131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator(
26231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                languageOnSpacebarFadeoutAnimatorResId, this);
26331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator(
26431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                altCodeKeyWhileTypingFadeoutAnimatorResId, this);
26531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator(
26631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                altCodeKeyWhileTypingFadeinAnimatorResId, this);
267f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka
268f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka        mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
269741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka
2702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarHorizontalMargin = (int)getResources().getDimension(
2712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.dimen.config_language_on_spacebar_horizontal_margin);
27231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
27331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
27452876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    @Override
27552876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
27652876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa        super.setHardwareAcceleratedDrawingEnabled(enabled);
277cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mDrawingPreviewPlacerView.setHardwareAcceleratedDrawingEnabled(enabled);
27852876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa    }
27952876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa
280dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    private ObjectAnimator loadObjectAnimator(final int resId, final Object target) {
28120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (resId == 0) {
28257372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka            // TODO: Stop returning null.
28320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return null;
28420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
28531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator(
28631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                getContext(), resId);
287d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka        if (animator != null) {
28831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka            animator.setTarget(target);
28973a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka        }
29031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return animator;
29131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
29273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka
2932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel,
2942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            final ObjectAnimator animatorToStart) {
2952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (animatorToCancel == null || animatorToStart == null) {
2962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            // TODO: Stop using null as a no-operation animator.
2972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return;
2982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
2992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        float startFraction = 0.0f;
3002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (animatorToCancel.isStarted()) {
3012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            animatorToCancel.cancel();
3022fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            startFraction = 1.0f - animatorToCancel.getAnimatedFraction();
3032fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
3042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final long startTime = (long)(animatorToStart.getDuration() * startFraction);
3052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        animatorToStart.start();
3062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        animatorToStart.setCurrentPlayTime(startTime);
3072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
3082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
3092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link TimerHander.Callbacks} method.
3102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
3112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void startWhileTypingFadeinAnimation() {
3122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        cancelAndStartAnimators(
3132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                mAltCodeKeyWhileTypingFadeoutAnimator, mAltCodeKeyWhileTypingFadeinAnimator);
3142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
3152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
3162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
3172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void startWhileTypingFadeoutAnimation() {
3182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        cancelAndStartAnimators(
3192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                mAltCodeKeyWhileTypingFadeinAnimator, mAltCodeKeyWhileTypingFadeoutAnimator);
3202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
3212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
32215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
32331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    public int getLanguageOnSpacebarAnimAlpha() {
32431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return mLanguageOnSpacebarAnimAlpha;
325d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka    }
326d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka
32715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
328dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setLanguageOnSpacebarAnimAlpha(final int alpha) {
32931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mLanguageOnSpacebarAnimAlpha = alpha;
33031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        invalidateKey(mSpaceKey);
33131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
33231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
33315f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
33431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    public int getAltCodeKeyWhileTypingAnimAlpha() {
33531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        return mAltCodeKeyWhileTypingAnimAlpha;
33631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka    }
33731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka
33815f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @ExternallyReferenced
339dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) {
3405141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        if (mAltCodeKeyWhileTypingAnimAlpha == alpha) {
3415141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            return;
3425141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3435141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        // Update the visual of alt-code-key-while-typing.
34431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka        mAltCodeKeyWhileTypingAnimAlpha = alpha;
3455141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        final Keyboard keyboard = getKeyboard();
3465141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        if (keyboard == null) {
3475141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            return;
3485141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3495141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        for (final Key key : keyboard.mAltCodeKeysWhileTyping) {
3505141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka            invalidateKey(key);
3515141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka        }
3525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
354dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setKeyboardActionListener(final KeyboardActionListener listener) {
3555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        mKeyboardActionListener = listener;
3565c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka        PointerTracker.setKeyboardActionListener(listener);
3575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
3592fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // TODO: We should reconsider which coordinate system should be used to represent keyboard
3602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // event.
3612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public int getKeyX(final int x) {
3622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return Constants.isValidCoordinate(x) ? mKeyDetector.getTouchX(x) : x;
3635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
3645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
3652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // TODO: We should reconsider which coordinate system should be used to represent keyboard
3662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // event.
3672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public int getKeyY(final int y) {
3682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return Constants.isValidCoordinate(y) ? mKeyDetector.getTouchY(y) : y;
3690efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka    }
3700efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka
3715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    /**
3725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * Attaches a keyboard to this view. The keyboard can be switched at any time and the
3735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * view will re-layout itself to accommodate the keyboard.
3745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @see Keyboard
3755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @see #getKeyboard()
3765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @param keyboard the keyboard to display in this view
3775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     */
3785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
379dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setKeyboard(final Keyboard keyboard) {
3805cbda70956af14453fca7395d892c59aabbd8fd3Jean Chalard        // Remove any pending messages, except dismissing preview and key repeat.
3815cbda70956af14453fca7395d892c59aabbd8fd3Jean Chalard        mKeyTimerHandler.cancelLongPressTimers();
3825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        super.setKeyboard(keyboard);
3835a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka        mKeyDetector.setKeyboard(
38408ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
3858335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        PointerTracker.setKeyDetector(mKeyDetector);
386a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        mMoreKeysKeyboardCache.clear();
3874112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
388240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka        mSpaceKey = keyboard.getKey(Constants.CODE_SPACE);
3894112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
3902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        mLanguageOnSpacebarTextSize = keyHeight * mLanguageOnSpacebarTextRatio;
391f147794fd41491a3383e6aca6d49007f58124068alanv
392d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
393dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka            if (mAccessibilityDelegate == null) {
394dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka                mAccessibilityDelegate = new MainKeyboardAccessibilityDelegate(this, mKeyDetector);
395dec599d1723f4ff52f066bd2dd1a4457d30cd33cTadashi G. Takaoka            }
396ae0fab9550f1d9159d819dbb0b7cc86c2bf2937cTadashi G. Takaoka            mAccessibilityDelegate.setKeyboard(keyboard);
397d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        } else {
398ae0fab9550f1d9159d819dbb0b7cc86c2bf2937cTadashi G. Takaoka            mAccessibilityDelegate = null;
399d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        }
4005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
4015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
4020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    /**
403ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * Enables or disables the key preview popup. This is a popup that shows a magnified
4040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * version of the depressed key. By default the preview is enabled.
4050e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * @param previewEnabled whether or not to enable the key feedback preview
4060e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     * @param delay the delay after which the preview is dismissed
4070e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka     */
4080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) {
4097d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka        mKeyPreviewDrawParams.setPopupEnabled(previewEnabled, delay);
4100e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
4110e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
412ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    /**
413ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * Enables or disables the key preview popup animations and set animations' parameters.
414ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     *
415ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param hasCustomAnimationParams false to use the default key preview popup animations
416ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     *   specified by keyPreviewShowUpAnimator and keyPreviewDismissAnimator attributes.
417ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     *   true to override the default animations with the specified parameters.
418ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param showUpStartXScale from this x-scale the show up animation will start.
419ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param showUpStartYScale from this y-scale the show up animation will start.
420ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param showUpDuration the duration of the show up animation in milliseconds.
421ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param dismissEndXScale to this x-scale the dismiss animation will end.
422ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param dismissEndYScale to this y-scale the dismiss animation will end.
423ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     * @param dismissDuration the duration of the dismiss animation in milliseconds.
424ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka     */
425ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka    public void setKeyPreviewAnimationParams(final boolean hasCustomAnimationParams,
426ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration,
427ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka            final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) {
428ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka        mKeyPreviewDrawParams.setAnimationParams(hasCustomAnimationParams,
429ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                showUpStartXScale, showUpStartYScale, showUpDuration,
430ac88f3d8459e17236654aa38debea749ecb631d1Tadashi G. Takaoka                dismissEndXScale, dismissEndYScale, dismissDuration);
431276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka    }
432276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka
433375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    private void locatePreviewPlacerView() {
434375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        getLocationInWindow(mOriginCoords);
4350c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        mDrawingPreviewPlacerView.setKeyboardViewGeometry(mOriginCoords, getWidth(), getHeight());
4360c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka    }
4370c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka
4380c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka    private void installPreviewPlacerView() {
439375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        final View rootView = getRootView();
440375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        if (rootView == null) {
441375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka            Log.w(TAG, "Cannot find root view");
442375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka            return;
443375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        }
444375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content);
445375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        // Note: It'd be very weird if we get null by android.R.id.content.
446375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        if (windowContentView == null) {
447cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka            Log.w(TAG, "Cannot find android.R.id.content view to add DrawingPreviewPlacerView");
4480c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka            return;
449375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        }
4500c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        windowContentView.addView(mDrawingPreviewPlacerView);
451375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
452375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
4532fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link DrawingHandler.Callbacks} method.
4542fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
4552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void dismissAllKeyPreviews() {
456bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer.dismissAllKeyPreviews();
457375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        PointerTracker.setReleasedKeyGraphicsToAllKeys();
458375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
459375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
4600e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
4612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void showKeyPreview(final Key key) {
462a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        // If the key is invalid or has no key preview, we must not show key preview.
463a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        if (key == null || key.noKeyPreview()) {
4640e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka            return;
4650e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        }
4662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final Keyboard keyboard = getKeyboard();
467a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        if (keyboard == null) {
468a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka            return;
469a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        }
470a68e0dd437daa1387edc65082f96a00ca258a7b0Tadashi G. Takaoka        final KeyPreviewDrawParams previewParams = mKeyPreviewDrawParams;
4717d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka        if (!previewParams.isPopupEnabled()) {
472992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka            previewParams.setVisibleOffset(-keyboard.mVerticalGap);
4732fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return;
4742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
4752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
476bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        locatePreviewPlacerView();
4770e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        getLocationInWindow(mOriginCoords);
47884405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka        mKeyPreviewChoreographer.placeAndShowKeyPreview(key, keyboard.mIconsSet, mKeyDrawParams,
4793ff72dd0daa9baaeb4d6b8ade59d65c1f0e8b34fTadashi G. Takaoka                getWidth(), mOriginCoords, mDrawingPreviewPlacerView, isHardwareAccelerated());
4802fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
4812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
4822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link TimerHandler.Callbacks} method.
4830e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
4842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void dismissKeyPreviewWithoutDelay(final Key key) {
485bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer.dismissKeyPreview(key, false /* withAnimation */);
4862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // To redraw key top letter.
4872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        invalidateKey(key);
4882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    }
4892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
4902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
4912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void dismissKeyPreview(final Key key) {
4922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (!isHardwareAccelerated()) {
4932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            // TODO: Implement preference option to control key preview method and duration.
4947d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka            mDrawingHandler.dismissKeyPreview(mKeyPreviewDrawParams.getLingerTimeout(), key);
4952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return;
4962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
497bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka        mKeyPreviewChoreographer.dismissKeyPreview(key, true /* withAnimation */);
4980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
4990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
500ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka    public void setSlidingKeyInputPreviewEnabled(final boolean enabled) {
501cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.setPreviewEnabled(enabled);
502ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka    }
503ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka
5040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
5050e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    public void showSlidingKeyInputPreview(final PointerTracker tracker) {
5060e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka        locatePreviewPlacerView();
507cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.setPreviewPosition(tracker);
5080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
5090e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
5100e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    @Override
5110e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    public void dismissSlidingKeyInputPreview() {
512cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mSlidingKeyInputDrawingPreview.dismissSlidingKeyInputPreview();
5130e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka    }
5140e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka
515724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa    private void setGesturePreviewMode(final boolean isGestureTrailEnabled,
516724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureFloatingPreviewTextEnabled) {
517cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.setPreviewEnabled(isGestureFloatingPreviewTextEnabled);
518cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setPreviewEnabled(isGestureTrailEnabled);
519375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
520375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
5212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link DrawingHandler.Callbacks} method.
5222fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
523375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) {
524375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        locatePreviewPlacerView();
525cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureFloatingTextDrawingPreview.setSuggetedWords(suggestedWords);
526375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
527375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
528375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    public void dismissGestureFloatingPreviewText() {
529375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        locatePreviewPlacerView();
530375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mDrawingHandler.dismissGestureFloatingPreviewText(mGestureFloatingPreviewTextLingerTimeout);
531375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
532375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
533fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka    @Override
534212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka    public void showGestureTrail(final PointerTracker tracker,
535212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka            final boolean showsFloatingPreviewText) {
536375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        locatePreviewPlacerView();
537212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka        if (showsFloatingPreviewText) {
538cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka            mGestureFloatingTextDrawingPreview.setPreviewPosition(tracker);
539212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka        }
540cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mGestureTrailsDrawingPreview.setPreviewPosition(tracker);
541375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
542375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
5438335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka    // Note that this method is called from a non-UI thread.
544c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka    @SuppressWarnings("static-method")
545dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) {
5468335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable);
5478335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka    }
5488335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka
549724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa    public void setGestureHandlingEnabledByUser(final boolean isGestureHandlingEnabledByUser,
550724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureTrailEnabled,
551724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa            final boolean isGestureFloatingPreviewTextEnabled) {
552724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa        PointerTracker.setGestureHandlingEnabledByUser(isGestureHandlingEnabledByUser);
553724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa        setGesturePreviewMode(isGestureHandlingEnabledByUser && isGestureTrailEnabled,
554724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa                isGestureHandlingEnabledByUser && isGestureFloatingPreviewTextEnabled);
5550657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka    }
5560657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka
5575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
5584331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    protected void onAttachedToWindow() {
5594331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        super.onAttachedToWindow();
5600c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka        installPreviewPlacerView();
561c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    }
562c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka
563c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    @Override
564c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    protected void onDetachedFromWindow() {
565c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka        super.onDetachedFromWindow();
566cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        mDrawingPreviewPlacerView.removeAllViews();
5674331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
5684331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
569a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka    private MoreKeysPanel onCreateMoreKeysPanel(final Key key, final Context context) {
57003288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        final MoreKeySpec[] moreKeys = key.getMoreKeys();
57103288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        if (moreKeys == null) {
5725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka            return null;
57320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
574a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        Keyboard moreKeysKeyboard = mMoreKeysKeyboardCache.get(key);
575a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (moreKeysKeyboard == null) {
57603288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link KeyPreviewDrawParams#mPreviewVisibleWidth} should have been set at
57703288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link KeyPreviewChoreographer#placeKeyPreview(Key,TextView,KeyboardIconsSet,KeyDrawParams,int,int[]},
57803288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // though there may be some chances that the value is zero. <code>width == 0</code>
57903288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // will cause zero-division error at
58003288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            // {@link MoreKeysKeyboardParams#setParameters(int,int,int,int,int,int,boolean,int)}.
58184405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka            final boolean isSingleMoreKeyWithPreview = mKeyPreviewDrawParams.isPopupEnabled()
58203288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    && !key.noKeyPreview() && moreKeys.length == 1
58303288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    && mKeyPreviewDrawParams.getVisibleWidth() > 0;
58403288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            final MoreKeysKeyboard.Builder builder = new MoreKeysKeyboard.Builder(
58584405d2a6815a99992849e821e073835f2d892e3Tadashi G. Takaoka                    context, key, getKeyboard(), isSingleMoreKeyWithPreview,
58603288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    mKeyPreviewDrawParams.getVisibleWidth(),
58703288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                    mKeyPreviewDrawParams.getVisibleHeight(), newLabelPaint(key));
58803288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka            moreKeysKeyboard = builder.build();
589a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka            mMoreKeysKeyboardCache.put(key, moreKeysKeyboard);
59020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
5915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
5920f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka        final View container = key.isActionKey() ? mMoreKeysKeyboardForActionContainer
5930f33e614c0799fa3a14a2c32db4bf0654df039daTadashi G. Takaoka                : mMoreKeysKeyboardContainer;
5942affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        final MoreKeysKeyboardView moreKeysKeyboardView =
5952affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka                (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view);
5962affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        moreKeysKeyboardView.setKeyboard(moreKeysKeyboard);
597b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka        container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
5982affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        return moreKeysKeyboardView;
5995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
6005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
6012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    // Implements {@link TimerHandler.Callbacks} method.
6025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    /**
603d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka     * Called when a key is long pressed.
6045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     * @param tracker the pointer tracker which pressed the parent key
6055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka     */
6062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    @Override
6072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public void onLongPress(final PointerTracker tracker) {
608a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (isShowingMoreKeysPanel()) {
60996efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka            return;
610a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        }
611a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        final Key key = tracker.getKey();
612a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (key == null) {
61396efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka            return;
614a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        }
615f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka        final KeyboardActionListener listener = mKeyboardActionListener;
6169552badf3c24d2098d227b0ddca0721b928a10b1Tadashi G. Takaoka        if (key.hasNoPanelAutoMoreKey()) {
6177dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka            final int moreKeyCode = key.getMoreKeys()[0].mCode;
6183708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka            tracker.onLongPressed();
619ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            listener.onPressKey(moreKeyCode, 0 /* repeatCount */, true /* isSinglePointer */);
6202282e8520a2c1984989a14fb09896536f5033b26Jean Chalard            listener.onCodeInput(moreKeyCode, Constants.NOT_A_COORDINATE,
6212282e8520a2c1984989a14fb09896536f5033b26Jean Chalard                    Constants.NOT_A_COORDINATE, false /* isKeyRepeat */);
622f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka            listener.onReleaseKey(moreKeyCode, false /* withSliding */);
62396efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka            return;
6243708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka        }
6257dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int code = key.getCode();
626a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) {
6273708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka            // Long pressing the space key invokes IME switcher dialog.
628f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka            if (listener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) {
6296dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka                tracker.onLongPressed();
630f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka                listener.onReleaseKey(code, false /* withSliding */);
63196efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka                return;
6326dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka            }
6336dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka        }
63496efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka        openMoreKeysPanel(key, tracker);
6356dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka    }
6366dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka
63796efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka    private void openMoreKeysPanel(final Key key, final PointerTracker tracker) {
638a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        final MoreKeysPanel moreKeysPanel = onCreateMoreKeysPanel(key, getContext());
6399d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka        if (moreKeysPanel == null) {
64096efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka            return;
6415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        }
64263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka
643547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka        final int[] lastCoords = CoordinateUtils.newInstance();
644547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka        tracker.getLastCoordinates(lastCoords);
64503288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka        final boolean keyPreviewEnabled = mKeyPreviewDrawParams.isPopupEnabled()
64603288ef47fd93758b5665e19fe9b892ece6e586fTadashi G. Takaoka                && !key.noKeyPreview();
6477ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // The more keys keyboard is usually horizontally aligned with the center of the parent key.
6487ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // If showMoreKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more
6497ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // keys keyboard is placed at the touch point of the parent key.
6507ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint && !keyPreviewEnabled)
651547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka                ? CoordinateUtils.x(lastCoords)
6527dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka                : key.getX() + key.getWidth() / 2;
6537ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // The more keys keyboard is usually vertically aligned with the top edge of the parent key
6547ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // (plus vertical gap). If the key preview is enabled, the more keys keyboard is vertically
6557ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        // aligned with the bottom edge of the visible part of the key preview.
65629d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka        // {@code mPreviewVisibleOffset} has been set appropriately in
65729d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka        // {@link KeyboardView#showKeyPreview(PointerTracker)}.
658992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka        final int pointY = key.getY() + mKeyPreviewDrawParams.getVisibleOffset();
659fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        moreKeysPanel.showMoreKeysPanel(this, this, pointX, pointY, mKeyboardActionListener);
66033482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka        tracker.onShowMoreKeysPanel(moreKeysPanel);
6612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // TODO: Implement zoom in animation of more keys panel.
6622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        dismissKeyPreviewWithoutDelay(key);
6635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
6645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
6652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public boolean isInDraggingFinger() {
666a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        if (isShowingMoreKeysPanel()) {
66763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka            return true;
6685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        }
6692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return PointerTracker.isAnyInDraggingFinger();
6705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
6715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
672d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
673d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    public void onShowMoreKeysPanel(final MoreKeysPanel panel) {
6741b6eea89037158a1e271730eacdacb8b6e550d3aTadashi G. Takaoka        locatePreviewPlacerView();
675cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka        panel.showInParent(mDrawingPreviewPlacerView);
676d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mMoreKeysPanel = panel;
677a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        dimEntireKeyboard(true /* dimmed */);
678d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
679d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
680d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    public boolean isShowingMoreKeysPanel() {
681a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        return mMoreKeysPanel != null && mMoreKeysPanel.isShowingInParent();
682d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
683d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
684d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
6851f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka    public void onCancelMoreKeysPanel() {
686d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        PointerTracker.dismissAllMoreKeysPanels();
687d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
688d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
689d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    @Override
6901f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka    public void onDismissMoreKeysPanel() {
691d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        dimEntireKeyboard(false /* dimmed */);
692d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        if (isShowingMoreKeysPanel()) {
6937f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka            mMoreKeysPanel.removeFromParent();
694d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka            mMoreKeysPanel = null;
695d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        }
696d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    }
697d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka
6985433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public void startDoubleTapShiftKeyTimer() {
6995433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka        mKeyTimerHandler.startDoubleTapShiftKeyTimer();
7005433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
7015433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
7025433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public void cancelDoubleTapShiftKeyTimer() {
7035433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka        mKeyTimerHandler.cancelDoubleTapShiftKeyTimer();
7045433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
7055433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
7065433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    public boolean isInDoubleTapShiftKeyTimeout() {
7075433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka        return mKeyTimerHandler.isInDoubleTapShiftKeyTimeout();
7085433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka    }
7095433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka
7105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    @Override
711dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public boolean onTouchEvent(final MotionEvent me) {
71246286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka        if (getKeyboard() == null) {
71346286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka            return false;
71446286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka        }
715b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        if (mNonDistinctMultitouchHelper != null) {
716b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            if (me.getPointerCount() > 1 && mKeyTimerHandler.isInKeyRepeat()) {
717b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka                // Key repeating timer will be canceled if 2 or more keys are in action.
7182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                mKeyTimerHandler.cancelKeyRepeatTimers();
719b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            }
720b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            // Non distinct multitouch screen support
7212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            mNonDistinctMultitouchHelper.processMotionEvent(me, mKeyDetector);
722b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka            return true;
723b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka        }
724310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka        return processMotionEvent(me);
725c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka    }
726c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka
727dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public boolean processMotionEvent(final MotionEvent me) {
728e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka        final int index = me.getActionIndex();
729e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka        final int id = me.getPointerId(index);
7302fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final PointerTracker tracker = PointerTracker.getPointerTracker(id);
7312fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // When a more keys panel is showing, we should ignore other fingers' single touch events
7322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // other than the finger that is showing the more keys panel.
7332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (isShowingMoreKeysPanel() && !tracker.isShowingMoreKeysPanel()
7342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                && PointerTracker.getActivePointerTrackerCount() == 1) {
7352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            return true;
7362fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
7372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        tracker.processMotionEvent(me, mKeyDetector);
7385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        return true;
7395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
7405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
7415c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka    public void cancelAllOngoingEvents() {
742375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mKeyTimerHandler.cancelAllMessages();
743375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        mDrawingHandler.cancelAllMessages();
7445c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        dismissAllKeyPreviews();
7455c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        dismissGestureFloatingPreviewText();
7465c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        dismissSlidingKeyInputPreview();
7475c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        PointerTracker.dismissAllMoreKeysPanels();
7485c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        PointerTracker.cancelAllPointerTrackers();
749375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka    }
750375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka
7515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    public void closing() {
7525c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka        cancelAllOngoingEvents();
753a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        mMoreKeysKeyboardCache.clear();
7545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
7555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka
756bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka    public void onHideWindow() {
757a74719c934ceb30d2afb7ae999c909f5c6fd5325Tadashi G. Takaoka        onDismissMoreKeysPanel();
758d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
759ae3ad8ebdd1a3239e17fd14e50a8e9670cb5b61aTadashi G. Takaoka        if (accessibilityDelegate != null
760ae3ad8ebdd1a3239e17fd14e50a8e9670cb5b61aTadashi G. Takaoka                && AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
761d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka            accessibilityDelegate.onHideWindow();
7621ead609e6fd64fd5ac2979ac3802d8bada7d7f49Tadashi G. Takaoka        }
763bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka    }
764bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka
765586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette    /**
7669647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka     * {@inheritDoc}
767586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette     */
768c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka    @Override
7699647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka    public boolean onHoverEvent(final MotionEvent event) {
770d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka        final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
771ae3ad8ebdd1a3239e17fd14e50a8e9670cb5b61aTadashi G. Takaoka        if (accessibilityDelegate != null
772ae3ad8ebdd1a3239e17fd14e50a8e9670cb5b61aTadashi G. Takaoka                && AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
773d78b586976af9b6b8f6e00c04747facfac313abcTadashi G. Takaoka            return accessibilityDelegate.onHoverEvent(event);
7745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        }
7759647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka        return super.onHoverEvent(event);
7765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka    }
77722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka
778dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void updateShortcutKey(final boolean available) {
7797bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        final Keyboard keyboard = getKeyboard();
78020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (keyboard == null) {
78120dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return;
78220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
783240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka        final Key shortcutKey = keyboard.getKey(Constants.CODE_SHORTCUT);
78420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (shortcutKey == null) {
78520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return;
78620dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
7877bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        shortcutKey.setEnabled(available);
7887bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka        invalidateKey(shortcutKey);
7895afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka    }
7905afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka
791dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged,
7927dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            final int languageOnSpacebarFormatType,
7937dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            final boolean hasMultipleEnabledIMEsOrSubtypes) {
794016d6c424cf004c282db5a57e64f3d1eee672a22Tadashi G. Takaoka        if (subtypeChanged) {
795016d6c424cf004c282db5a57e64f3d1eee672a22Tadashi G. Takaoka            KeyPreviewView.clearTextCache();
796016d6c424cf004c282db5a57e64f3d1eee672a22Tadashi G. Takaoka        }
7977dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka        mLanguageOnSpacebarFormatType = languageOnSpacebarFormatType;
798fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka        mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes;
799fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka        final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator;
800d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka        if (animator == null) {
8017dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            mLanguageOnSpacebarFormatType = LanguageOnSpacebarHelper.FORMAT_TYPE_NONE;
8024c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka        } else {
8037dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            if (subtypeChanged
8047dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka                    && languageOnSpacebarFormatType != LanguageOnSpacebarHelper.FORMAT_TYPE_NONE) {
8054daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang                setLanguageOnSpacebarAnimAlpha(Constants.Color.ALPHA_OPAQUE);
80631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                if (animator.isStarted()) {
80731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                    animator.cancel();
80831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                }
809d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka                animator.start();
810dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka            } else {
81131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                if (!animator.isStarted()) {
81231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                    mLanguageOnSpacebarAnimAlpha = mLanguageOnSpacebarFinalAlpha;
81331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka                }
814dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka            }
8154c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka        }
8164112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        invalidateKey(mSpaceKey);
8174112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    }
8184112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
819a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka    private void dimEntireKeyboard(final boolean dimmed) {
820f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        final boolean needsRedrawing = mNeedsToDimEntireKeyboard != dimmed;
821f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        mNeedsToDimEntireKeyboard = dimmed;
822f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        if (needsRedrawing) {
823f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka            invalidateAllKeys();
824f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        }
825f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    }
826f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka
827f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    @Override
828f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    protected void onDraw(final Canvas canvas) {
829f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        super.onDraw(canvas);
830f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka
831f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        // Overlay a dark rectangle to dim.
832f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        if (mNeedsToDimEntireKeyboard) {
83308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka            canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mBackgroundDimAlphaPaint);
834f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka        }
835f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka    }
836f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka
83722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka    @Override
838dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka    protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint,
839dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka            final KeyDrawParams params) {
8406bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka        if (key.altCodeWhileTyping() && key.isEnabled()) {
84173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka            params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha;
84273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka        }
84341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        super.onDrawKeyTopVisuals(key, canvas, paint, params);
8447dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int code = key.getCode();
8457dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        if (code == Constants.CODE_SPACE) {
84641808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            // If input language are explicitly selected.
84741808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            if (mLanguageOnSpacebarFormatType != LanguageOnSpacebarHelper.FORMAT_TYPE_NONE) {
84841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka                drawLanguageOnSpacebar(key, canvas, paint);
84941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            }
8504112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka            // Whether space key needs to show the "..." popup hint for special purposes
851fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka            if (key.isLongPressEnabled() && mHasMultipleEnabledIMEsOrSubtypes) {
852bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka                drawKeyPopupHint(key, canvas, paint, params);
8534112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka            }
8547dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        } else if (code == Constants.CODE_LANGUAGE_SWITCH) {
855fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka            drawKeyPopupHint(key, canvas, paint, params);
85622b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka        }
85722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka    }
8584112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
859741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private boolean fitsTextIntoWidth(final int width, final String text, final Paint paint) {
860741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka        final int maxTextWidth = width - mLanguageOnSpacebarHorizontalMargin * 2;
861bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        paint.setTextScaleX(1.0f);
8622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final float textWidth = TypefaceUtils.getStringWidth(text, paint);
86320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (textWidth < width) {
86420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return true;
86520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
866bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
867741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka        final float scaleX = maxTextWidth / textWidth;
86820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (scaleX < MINIMUM_XSCALE_OF_LANGUAGE_NAME) {
86920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return false;
87020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        }
871bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
872bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        paint.setTextScaleX(scaleX);
8732fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        return TypefaceUtils.getStringWidth(text, paint) < maxTextWidth;
874bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    }
875bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
876bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka    // Layout language name on spacebar.
877741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka    private String layoutLanguageOnSpacebar(final Paint paint,
87808ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka            final InputMethodSubtype subtype, final int width) {
879bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        // Choose appropriate language name to fit into the width.
8807dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka        if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_FULL_LOCALE) {
8817dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            final String fullText = SpacebarLanguageUtils.getFullDisplayName(subtype);
8827dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            if (fitsTextIntoWidth(width, fullText, paint)) {
8837dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka                return fullText;
8847dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka            }
885bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        }
886bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka
8879364d46ac3590d23b8117a66efc8756454cef772Tadashi G. Takaoka        final String middleText = SpacebarLanguageUtils.getMiddleDisplayName(subtype);
88820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka        if (fitsTextIntoWidth(width, middleText, paint)) {
88920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka            return middleText;
8904112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        }
8914112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
892bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka        return "";
8934112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    }
8944112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka
89541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka    private void drawLanguageOnSpacebar(final Key key, final Canvas canvas, final Paint paint) {
8967dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int width = key.getWidth();
8977dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka        final int height = key.getHeight();
89841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTextAlign(Align.CENTER);
89941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTypeface(Typeface.DEFAULT);
90041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTextSize(mLanguageOnSpacebarTextSize);
90141808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final InputMethodSubtype subtype = getKeyboard().mId.mSubtype;
90241808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final String language = layoutLanguageOnSpacebar(paint, subtype, width);
90341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        // Draw language text with shadow
90441808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final float descent = paint.descent();
90541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final float textHeight = -paint.ascent() + descent;
90641808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        final float baseline = height / 2 + textHeight / 2;
90741808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        if (mLanguageOnSpacebarTextShadowRadius > 0.0f) {
90841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka            paint.setShadowLayer(mLanguageOnSpacebarTextShadowRadius, 0, 0,
90941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka                    mLanguageOnSpacebarTextShadowColor);
91041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        } else {
91141f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka            paint.clearShadowLayer();
9124112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka        }
91341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setColor(mLanguageOnSpacebarTextColor);
91441808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setAlpha(mLanguageOnSpacebarAnimAlpha);
91541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        canvas.drawText(language, width / 2, baseline - descent, paint);
91641808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.clearShadowLayer();
91741808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka        paint.setTextScaleX(1.0f);
9184112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka    }
919c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa
920e68d565d0f9704145adbf781105f1ac9a90f0a98Ken Wakasa    @Override
921c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa    public void deallocateMemory() {
922e68d565d0f9704145adbf781105f1ac9a90f0a98Ken Wakasa        super.deallocateMemory();
923afca1ddd233c03d79433931a0b6ba97ed22663edTadashi G. Takaoka        mDrawingPreviewPlacerView.deallocateMemory();
924c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa    }
9255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka}
926