MainKeyboardView.java revision 6dde878d515f7bf5268d16a8fe4921d8821c5ae7
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 195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.Context; 205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.pm.PackageManager; 215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.res.Resources; 225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.content.res.TypedArray; 236dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport android.graphics.Canvas; 245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.os.Message; 2563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaokaimport android.os.SystemClock; 265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.AttributeSet; 275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.util.Log; 285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.GestureDetector; 295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.LayoutInflater; 305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.MotionEvent; 315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.View; 325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.ViewConfiguration; 335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.view.accessibility.AccessibilityEvent; 345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport android.widget.PopupWindow; 355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibilityUtils; 375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 386dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport com.android.inputmethod.deprecated.VoiceProxy; 39f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; 402321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker.TimerProxy; 415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.MiniKeyboardBuilder; 426dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinIME; 435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport com.android.inputmethod.latin.StaticInnerHandlerWrapper; 456dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokaimport com.android.inputmethod.latin.Utils; 465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokaimport java.util.WeakHashMap; 485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/** 505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * A view that is responsible for detecting key presses and touch movements. 515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @attr ref R.styleable#KeyboardView_keyHysteresisDistance 535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @attr ref R.styleable#KeyboardView_verticalCorrection 545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @attr ref R.styleable#KeyboardView_popupLayout 555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 56f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaokapublic class LatinKeyboardBaseView extends KeyboardView implements PointerTracker.KeyEventHandler { 575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private static final String TAG = LatinKeyboardBaseView.class.getSimpleName(); 585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true; 605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Timing constants 625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private final int mKeyRepeatInterval; 635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // XML attribute 655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private final float mVerticalCorrection; 665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private final int mPopupLayout; 675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Mini keyboard 695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private PopupWindow mPopupWindow; 7063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka private PopupPanel mPopupPanel; 7163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka private int mPopupPanelPointerTrackerId; 725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private final WeakHashMap<Key, PopupPanel> mPopupPanelCache = 735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka new WeakHashMap<Key, PopupPanel>(); 745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** Listener for {@link KeyboardActionListener}. */ 765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private KeyboardActionListener mKeyboardActionListener; 775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private final boolean mHasDistinctMultitouch; 795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private int mOldPointerCount = 1; 805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private int mOldKeyIndex; 815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 82a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka protected KeyDetector mKeyDetector; 835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 84c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka // To detect double tap. 855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka protected GestureDetector mGestureDetector; 865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 87f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private final KeyTimerHandler mKeyTimerHandler = new KeyTimerHandler(this); 885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 892321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka private static class KeyTimerHandler extends StaticInnerHandlerWrapper<LatinKeyboardBaseView> 902321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka implements TimerProxy { 91f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_REPEAT_KEY = 1; 92f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka private static final int MSG_LONGPRESS_KEY = 2; 9398b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka private static final int MSG_IGNORE_DOUBLE_TAP = 3; 945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private boolean mInKeyRepeat; 965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 97f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka public KeyTimerHandler(LatinKeyboardBaseView outerInstance) { 985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(outerInstance); 995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 1025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void handleMessage(Message msg) { 1035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final LatinKeyboardBaseView keyboardView = getOuterInstance(); 1045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = (PointerTracker) msg.obj; 1055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka switch (msg.what) { 1065f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_REPEAT_KEY: 1075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka tracker.onRepeatKey(msg.arg1); 1085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka startKeyRepeatTimer(keyboardView.mKeyRepeatInterval, msg.arg1, tracker); 1095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 1105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case MSG_LONGPRESS_KEY: 1115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka keyboardView.openMiniKeyboardIfRequired(msg.arg1, tracker); 1125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 1135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1162321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 1175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) { 1185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mInKeyRepeat = true; 1195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0, tracker), delay); 1205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelKeyRepeatTimer() { 1235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mInKeyRepeat = false; 1245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_REPEAT_KEY); 1255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInKeyRepeat() { 1285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mInKeyRepeat; 1295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1312321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 1325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) { 13398b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka cancelLongPressTimer(); 1345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay); 1355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1372321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 13898b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer() { 1395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_LONGPRESS_KEY); 1405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1422321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka @Override 1435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelKeyTimers() { 1445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka cancelKeyRepeatTimer(); 14598b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka cancelLongPressTimer(); 1465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka removeMessages(MSG_IGNORE_DOUBLE_TAP); 1475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void startIgnoringDoubleTap() { 1505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_IGNORE_DOUBLE_TAP), 1515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka ViewConfiguration.getDoubleTapTimeout()); 1525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isIgnoringDoubleTap() { 1555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return hasMessages(MSG_IGNORE_DOUBLE_TAP); 1565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelAllMessages() { 1595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka cancelKeyTimers(); 1605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 1625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 163c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener { 164c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka private boolean mProcessingShiftDoubleTapEvent = false; 165c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 166c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka @Override 167c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka public boolean onDoubleTap(MotionEvent firstDown) { 168c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 169c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka if (ENABLE_CAPSLOCK_BY_DOUBLETAP && keyboard instanceof LatinKeyboard 170c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka && ((LatinKeyboard) keyboard).isAlphaKeyboard()) { 171c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final int pointerIndex = firstDown.getActionIndex(); 172c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final int id = firstDown.getPointerId(pointerIndex); 173c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final PointerTracker tracker = getPointerTracker(id); 174c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka // If the first down event is on shift key. 175c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka if (tracker.isOnShiftKey((int) firstDown.getX(), (int) firstDown.getY())) { 176c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka mProcessingShiftDoubleTapEvent = true; 177c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka return true; 178c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 179c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 180c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka mProcessingShiftDoubleTapEvent = false; 181c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka return false; 182c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 183c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 184c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka @Override 185c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka public boolean onDoubleTapEvent(MotionEvent secondTap) { 186c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka if (mProcessingShiftDoubleTapEvent 187c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka && secondTap.getAction() == MotionEvent.ACTION_DOWN) { 188c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final MotionEvent secondDown = secondTap; 189c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final int pointerIndex = secondDown.getActionIndex(); 190c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final int id = secondDown.getPointerId(pointerIndex); 191c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final PointerTracker tracker = getPointerTracker(id); 192c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka // If the second down event is also on shift key. 193c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka if (tracker.isOnShiftKey((int) secondDown.getX(), (int) secondDown.getY())) { 194c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka // Detected a double tap on shift key. If we are in the ignoring double tap 195c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka // mode, it means we have already turned off caps lock in 196c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka // {@link KeyboardSwitcher#onReleaseShift} . 197c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka final boolean ignoringDoubleTap = mKeyTimerHandler.isIgnoringDoubleTap(); 198c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka if (!ignoringDoubleTap) 199c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka onDoubleTapShiftKey(tracker); 200c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka return true; 201c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 202c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka // Otherwise these events should not be handled as double tap. 203c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka mProcessingShiftDoubleTapEvent = false; 204c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 205c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka return mProcessingShiftDoubleTapEvent; 206c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 207c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka } 208c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka 2095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public LatinKeyboardBaseView(Context context, AttributeSet attrs) { 2105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka this(context, attrs, R.attr.keyboardViewStyle); 2115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public LatinKeyboardBaseView(Context context, AttributeSet attrs, int defStyle) { 2145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super(context, attrs, defStyle); 2155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 2175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); 2185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mVerticalCorrection = a.getDimensionPixelOffset( 2195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka R.styleable.KeyboardView_verticalCorrection, 0); 2205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupLayout = a.getResourceId(R.styleable.KeyboardView_popupLayout, 0); 2215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka a.recycle(); 2225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final Resources res = getResources(); 224a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka final float keyHysteresisDistance = res.getDimension(R.dimen.key_hysteresis_distance); 225a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = new KeyDetector(keyHysteresisDistance); 2265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final boolean ignoreMultitouch = true; 228c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka mGestureDetector = new GestureDetector( 229c71854a6614d1945739dcf40db61b0e887442b67Tadashi G. Takaoka getContext(), new DoubleTapListener(), null, ignoreMultitouch); 2305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mGestureDetector.setIsLongpressEnabled(false); 2315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mHasDistinctMultitouch = context.getPackageManager() 2335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); 2345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); 235906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka 2365c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.init(mHasDistinctMultitouch, getContext()); 2375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void startIgnoringDoubleTap() { 2405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (ENABLE_CAPSLOCK_BY_DOUBLETAP) 241f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.startIgnoringDoubleTap(); 2425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2445a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka public void setKeyboardActionListener(KeyboardActionListener listener) { 2455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyboardActionListener = listener; 2465c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.setKeyboardActionListener(listener); 2475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 2505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns the {@link KeyboardActionListener} object. 2515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return the listener attached to this keyboard 2525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 2530efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 2540efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener() { 2555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mKeyboardActionListener; 2565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 2575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 258bb4be5444b845655c0eb80bcfbb66f93603802eaTadashi G. Takaoka @Override 2590efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public KeyDetector getKeyDetector() { 2600efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyDetector; 2610efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 2620efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 2630efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka @Override 264f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy() { 265f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka return this; 266f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 267f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 268f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka @Override 2690efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka public TimerProxy getTimerProxy() { 2700efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka return mKeyTimerHandler; 2710efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 2720efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka 2736dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka @Override 2746dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { 2756dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 2766dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka if (keyboard instanceof LatinKeyboard) { 2776dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka final LatinKeyboard latinKeyboard = (LatinKeyboard)keyboard; 2786dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka if (latinKeyboard.isPhoneKeyboard() || latinKeyboard.isNumberKeyboard()) { 2796dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka // Phone and number keyboard never shows popup preview. 2806dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka super.setKeyPreviewPopupEnabled(false, delay); 2816dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka return; 2826dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 2836dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 2846dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka super.setKeyPreviewPopupEnabled(previewEnabled, delay); 2856dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 2866dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 2875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 2885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Attaches a keyboard to this view. The keyboard can be switched at any time and the 2895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * view will re-layout itself to accommodate the keyboard. 2905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see Keyboard 2915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @see #getKeyboard() 2925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param keyboard the keyboard to display in this view 2935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 2945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 2955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void setKeyboard(Keyboard keyboard) { 2965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Remove any pending messages, except dismissing preview 297f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelKeyTimers(); 2985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.setKeyboard(keyboard); 2995a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyDetector.setKeyboard( 3005a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka keyboard, -getPaddingLeft(), -getPaddingTop() + mVerticalCorrection); 3018da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mKeyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); 3025c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.setKeyDetector(mKeyDetector); 3035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupPanelCache.clear(); 3045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3065f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 3075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns whether the device has distinct multi-touch panel. 3085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return true if the device has distinct multi-touch panel. 3095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 3105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean hasDistinctMultitouch() { 3115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mHasDistinctMultitouch; 3125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 3155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * When enabled, calls to {@link KeyboardActionListener#onCodeInput} will include key 3165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * codes for adjacent keys. When disabled, only the primary key code will be 3175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * reported. 3185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param enabled whether or not the proximity correction is enabled 3195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 3205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void setProximityCorrectionEnabled(boolean enabled) { 3215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyDetector.setProximityCorrectionEnabled(enabled); 3225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 3255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Returns true if proximity correction is enabled. 3265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 3275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isProximityCorrectionEnabled() { 3285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mKeyDetector.isProximityCorrectionEnabled(); 3295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 3325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelAllMessages() { 333f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelAllMessages(); 3345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.cancelAllMessages(); 3355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private boolean openMiniKeyboardIfRequired(int keyIndex, PointerTracker tracker) { 3385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Check if we have a popup layout specified first. 3395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (mPopupLayout == 0) { 3405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 3415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 34363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka // Check if we are already displaying popup panel. 34463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka if (mPopupPanel != null) 34563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return false; 3465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final Key parentKey = tracker.getKey(keyIndex); 3475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (parentKey == null) 3485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 34963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return onLongPress(parentKey, tracker); 3505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private void onDoubleTapShiftKey(@SuppressWarnings("unused") PointerTracker tracker) { 3535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // When shift key is double tapped, the first tap is correctly processed as usual tap. And 3545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // the second tap is treated as this double tap event, so that we need not mark tracker 355906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka // calling setAlreadyProcessed() nor remove the tracker from mPointerQueue. 3565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0); 3575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // This default implementation returns a popup mini keyboard panel. 3605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka protected PopupPanel onCreatePopupPanel(Key parentKey) { 3615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (parentKey.mPopupCharacters == null) 3625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return null; 3635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final View container = LayoutInflater.from(getContext()).inflate(mPopupLayout, null); 3655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (container == null) 3665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka throw new NullPointerException(); 3675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PopupMiniKeyboardView miniKeyboardView = 3695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka (PopupMiniKeyboardView)container.findViewById(R.id.mini_keyboard_view); 3705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final Keyboard parentKeyboard = getKeyboard(); 3715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final Keyboard miniKeyboard = new MiniKeyboardBuilder( 3728da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka this, parentKeyboard.mPopupKeyboardResId, parentKey, parentKeyboard).build(); 3735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka miniKeyboardView.setKeyboard(miniKeyboard); 3745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), 3765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 3775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return miniKeyboardView; 3795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 3825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka protected boolean needsToDimKeyboard() { 38363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return mPopupPanel != null; 3845f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 3866dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboard oldKeyboard) { 3876dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 3886dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka // We should not set text fade factor to the keyboard which does not display the language on 3896dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka // its spacebar. 3906dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka if (keyboard instanceof LatinKeyboard && keyboard == oldKeyboard) { 3916dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka ((LatinKeyboard)keyboard).setSpacebarTextFadeFactor(fadeFactor, this); 3926dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 3936dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 3946dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 3955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka /** 3965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Called when a key is long pressed. By default this will open mini keyboard associated 3975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * with this key. 3985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param parentKey the key that was long pressed 3995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @param tracker the pointer tracker which pressed the parent key 4005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * @return true if the long press is handled, false otherwise. Subclasses should call the 4015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * method on the base class if the subclass doesn't wish to handle the call. 4025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 4035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka protected boolean onLongPress(Key parentKey, PointerTracker tracker) { 4046dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka final int primaryCode = parentKey.mCode; 4056dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka final Keyboard keyboard = getKeyboard(); 4066dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka if (keyboard instanceof LatinKeyboard) { 4076dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka final LatinKeyboard latinKeyboard = (LatinKeyboard) keyboard; 4086dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka if (primaryCode == Keyboard.CODE_DIGIT0 && latinKeyboard.isPhoneKeyboard()) { 4096dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 4106dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka // Long pressing on 0 in phone number keypad gives you a '+'. 4116dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka return invokeOnKey(Keyboard.CODE_PLUS); 4126dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 4136dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka if (primaryCode == Keyboard.CODE_SHIFT && latinKeyboard.isAlphaKeyboard()) { 4146dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 4156dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka return invokeOnKey(Keyboard.CODE_CAPSLOCK); 4166dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 4176dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 4186dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka if (primaryCode == Keyboard.CODE_SETTINGS || primaryCode == Keyboard.CODE_SPACE) { 4196dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka // Both long pressing settings key and space key invoke IME switcher dialog. 4206dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka if (getKeyboardActionListener().onCustomRequest( 4216dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { 4226dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tracker.onLongPressed(); 4236dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka return true; 4246dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } else { 4256dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka return openPopupPanel(parentKey, tracker); 4266dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 4276dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } else { 4286dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka return openPopupPanel(parentKey, tracker); 4296dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 4306dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 4316dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 4326dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka private boolean invokeOnKey(int primaryCode) { 4336dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka getKeyboardActionListener().onCodeInput(primaryCode, null, 4346dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka KeyboardActionListener.NOT_A_TOUCH_COORDINATE, 4356dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka KeyboardActionListener.NOT_A_TOUCH_COORDINATE); 4366dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka return true; 4376dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 4386dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 4396dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka private boolean openPopupPanel(Key parentKey, PointerTracker tracker) { 4405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka PopupPanel popupPanel = mPopupPanelCache.get(parentKey); 4415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (popupPanel == null) { 4425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka popupPanel = onCreatePopupPanel(parentKey); 4435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (popupPanel == null) 4445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 4455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupPanelCache.put(parentKey, popupPanel); 4465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (mPopupWindow == null) { 4485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupWindow = new PopupWindow(getContext()); 4495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupWindow.setBackgroundDrawable(null); 4505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupWindow.setAnimationStyle(R.style.PopupMiniKeyboardAnimation); 4515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Allow popup window to be drawn off the screen. 4525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupWindow.setClippingEnabled(false); 4535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 45463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mPopupPanel = popupPanel; 45563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mPopupPanelPointerTrackerId = tracker.mPointerId; 45663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka 4579ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka popupPanel.showPopupPanel(this, parentKey, tracker, mPopupWindow); 45863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka final int translatedX = popupPanel.translateX(tracker.getLastX()); 45963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka final int translatedY = popupPanel.translateY(tracker.getLastY()); 4609ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka tracker.onShowPopupPanel(translatedX, translatedY, SystemClock.uptimeMillis(), popupPanel); 4615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka invalidateAllKeys(); 4635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 4645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka private PointerTracker getPointerTracker(final int id) { 4675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return PointerTracker.getPointerTracker(id, this); 4685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 47163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka if (mPopupPanel != null) { 47263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka return true; 47363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } else { 4745c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return PointerTracker.isAnyInSlidingKeyInput(); 4755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public int getPointerCount() { 4795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return mOldPointerCount; 4805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4825f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 4835f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean onTouchEvent(MotionEvent me) { 484f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final boolean nonDistinctMultitouch = !mHasDistinctMultitouch; 4855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int action = me.getActionMasked(); 4865f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int pointerCount = me.getPointerCount(); 4875f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int oldPointerCount = mOldPointerCount; 4885f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mOldPointerCount = pointerCount; 4895f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4905f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 4915f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // If the device does not have distinct multi-touch support panel, ignore all multi-touch 4925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // events except a transition from/to single-touch. 493f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) { 4945f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 4955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 4965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 4975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Gesture detector must be enabled only when mini-keyboard is not on the screen. 49863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka if (mPopupPanel == null && mGestureDetector != null 4995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka && mGestureDetector.onTouchEvent(me)) { 5005c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka PointerTracker.dismissAllKeyPreviews(); 501f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelKeyTimers(); 5025f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 5035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final long eventTime = me.getEventTime(); 5065f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int index = me.getActionIndex(); 5075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int id = me.getPointerId(index); 50863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka final int x, y; 50963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka if (mPopupPanel != null && id == mPopupPanelPointerTrackerId) { 51063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka x = mPopupPanel.translateX((int)me.getX(index)); 51163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka y = mPopupPanel.translateY((int)me.getY(index)); 51263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } else { 51363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka x = (int)me.getX(index); 51463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka y = (int)me.getY(index); 5155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 517f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (mKeyTimerHandler.isInKeyRepeat()) { 5185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = getPointerTracker(id); 5195f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Key repeating timer will be canceled if 2 or more keys are in action, and current 5205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // event (UP or DOWN) is non-modifier key. 5215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount > 1 && !tracker.isModifier()) { 522f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mKeyTimerHandler.cancelKeyRepeatTimer(); 5235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5245f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Up event will pass through. 5255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5265f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5275f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // TODO: cleanup this code into a multi-touch to single-touch event converter class? 5285f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Translate mutli-touch event to single-touch events on the device that has no distinct 5295f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // multi-touch panel. 530f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka if (nonDistinctMultitouch) { 5315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Use only main (id=0) pointer tracker. 5325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka PointerTracker tracker = getPointerTracker(0); 5335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (pointerCount == 1 && oldPointerCount == 2) { 5345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Multi-touch to single touch transition. 5355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send a down event for the latest pointer if the key is different from the 5365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // previous key. 5375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int newKeyIndex = tracker.getKeyIndexOn(x, y); 5385f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (mOldKeyIndex != newKeyIndex) { 5390efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka tracker.onDownEvent(x, y, eventTime, this); 5405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (action == MotionEvent.ACTION_UP) 541906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka tracker.onUpEvent(x, y, eventTime); 5425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 2 && oldPointerCount == 1) { 5445f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Single-touch to multi-touch transition. 5455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Send an up event for the last pointer. 5465f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int lastX = tracker.getLastX(); 5475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final int lastY = tracker.getLastY(); 5485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mOldKeyIndex = tracker.getKeyIndexOn(lastX, lastY); 549906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka tracker.onUpEvent(lastX, lastY, eventTime); 5505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else if (pointerCount == 1 && oldPointerCount == 1) { 5510efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka processMotionEvent(tracker, action, x, y, eventTime, this); 5525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 5535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount 5545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka + " (old " + oldPointerCount + ")"); 5555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 5575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (action == MotionEvent.ACTION_MOVE) { 5605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka for (int i = 0; i < pointerCount; i++) { 5615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = getPointerTracker(me.getPointerId(i)); 56263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka final int px, py; 56363c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka if (mPopupPanel != null && tracker.mPointerId == mPopupPanelPointerTrackerId) { 56463c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka px = mPopupPanel.translateX((int)me.getX(i)); 56563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka py = mPopupPanel.translateY((int)me.getY(i)); 56663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } else { 56763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka px = (int)me.getX(i); 56863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka py = (int)me.getY(i); 56963c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka } 57063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka tracker.onMoveEvent(px, py, eventTime); 5715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } else { 5730efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka processMotionEvent(getPointerTracker(id), action, x, y, eventTime, this); 5745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 5775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 5785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 5793fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka private static void processMotionEvent(PointerTracker tracker, int action, int x, int y, 580f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka long eventTime, PointerTracker.KeyEventHandler handler) { 5813fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka switch (action) { 5823fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka case MotionEvent.ACTION_DOWN: 5833fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka case MotionEvent.ACTION_POINTER_DOWN: 584f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka tracker.onDownEvent(x, y, eventTime, handler); 5853fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka break; 5863fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka case MotionEvent.ACTION_UP: 5873fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka case MotionEvent.ACTION_POINTER_UP: 5883fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka tracker.onUpEvent(x, y, eventTime); 58904dec7f84de798482a5ddf9700e23ab561fe18fbTadashi G. Takaoka break; 59004dec7f84de798482a5ddf9700e23ab561fe18fbTadashi G. Takaoka case MotionEvent.ACTION_MOVE: 59104dec7f84de798482a5ddf9700e23ab561fe18fbTadashi G. Takaoka tracker.onMoveEvent(x, y, eventTime); 5923fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka break; 5933fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka case MotionEvent.ACTION_CANCEL: 5943fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka tracker.onCancelEvent(x, y, eventTime); 5953fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka break; 5963fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka } 5973fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka } 5983fdae97417b8ca33ae199c7817de7a80a3aeddaeTadashi G. Takaoka 5995f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 6005f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void closing() { 6015f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka super.closing(); 6029ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka dismissPopupPanel(); 6035f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupPanelCache.clear(); 6045f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6069ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka @Override 6079ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka public boolean dismissPopupPanel() { 6085f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (mPopupWindow != null && mPopupWindow.isShowing()) { 6095f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka mPopupWindow.dismiss(); 61063c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mPopupPanel = null; 61163c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mPopupPanelPointerTrackerId = -1; 6125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka invalidateAllKeys(); 6135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return true; 6145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 6165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean handleBack() { 6199ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka return dismissPopupPanel(); 6205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6225f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 6236dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka public void draw(Canvas c) { 6246dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka Utils.GCUtils.getInstance().reset(); 6256dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka boolean tryGC = true; 6266dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 6276dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka try { 6286dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka super.draw(c); 6296dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tryGC = false; 6306dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } catch (OutOfMemoryError e) { 6316dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait("LatinKeyboardView", e); 6326dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6336dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6346dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6356dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 6366dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka @Override 6376dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka protected void onAttachedToWindow() { 6386dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka // Token is available from here. 6396dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka VoiceProxy.getInstance().onAttachedToWindow(); 6406dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka } 6416dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 6426dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka @Override 6435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean dispatchTouchEvent(MotionEvent event) { 64465a898d9ef63e321deb06d1ede835c182e7bcce1Alan Viverette // Drop non-hover touch events when touch exploration is enabled. 6455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 64665a898d9ef63e321deb06d1ede835c182e7bcce1Alan Viverette return false; 6475f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6485f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6495f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return super.dispatchTouchEvent(event); 6505f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka @Override 6535f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 6555f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = getPointerTracker(0); 6565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return AccessibleKeyboardViewProxy.getInstance().dispatchPopulateAccessibilityEvent( 6575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka event, tracker) || super.dispatchPopulateAccessibilityEvent(event); 6585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6605f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return super.dispatchPopulateAccessibilityEvent(event); 6615f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 663586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette /** 664586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * Receives hover events from the input framework. This method overrides 665586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * View.dispatchHoverEvent(MotionEvent) on SDK version ICS or higher. On 666586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * lower SDK versions, this method is never called. 667586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * 668586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @param event The motion event to be dispatched. 669586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * @return {@code true} if the event was handled by the view, {@code false} 670586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette * otherwise 671586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette */ 672586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette public boolean dispatchHoverEvent(MotionEvent event) { 6735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 6745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka final PointerTracker tracker = getPointerTracker(0); 675586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette return AccessibleKeyboardViewProxy.getInstance().dispatchHoverEvent(event, tracker); 6765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 678586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette // Reflection doesn't support calling superclass methods. 6795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka return false; 6805f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 6815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka} 682