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