SuddenJumpingTouchEventHandler.java revision 0ce98cbf98c6409ac18fa341f467703d78352a4c
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 3923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 194fc510a7890976d9968d73ceacf3983e77f489d2satokimport com.android.inputmethod.latin.BaseKeyboard.Key; 204fc510a7890976d9968d73ceacf3983e77f489d2satok 21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Canvas; 231b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasaniimport android.graphics.Paint; 24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler; 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message; 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock; 2775c23ced94979a6b3f7c59e95dd46385e9702e2dKen Wakasaimport android.text.TextUtils; 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet; 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.MotionEvent; 30d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka 31d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaokaimport java.util.List; 32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 33979f8690967ff5409fe18f5085858ccdb8e0ccf1satokpublic class LatinKeyboardView extends LatinKeyboardBaseView { 34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 354189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka public static final int KEYCODE_OPTIONS = -100; 364189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka public static final int KEYCODE_OPTIONS_LONGPRESS = -101; 374189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka public static final int KEYCODE_VOICE = -102; 384189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka public static final int KEYCODE_F1 = -103; 394189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka public static final int KEYCODE_NEXT_LANGUAGE = -104; 404189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka public static final int KEYCODE_PREV_LANGUAGE = -105; 414189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka public static final int KEYCODE_CAPSLOCK = -106; 428eb2e34d5b2def57c9548f88e37e5c9e5a0bea59Amith Yamasani 430ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa private LatinKeyboard mPhoneKeyboard; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 450fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** Whether we've started dropping move events because we found a big jump */ 460fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private boolean mDroppingEvents; 47e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka /** 48d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka * Whether multi-touch disambiguation needs to be disabled if a real multi-touch event has 49d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka * occured 500fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani */ 510fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private boolean mDisableDisambiguation; 520fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** The distance threshold at which we start treating the touch session as a multi-touch */ 530fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private int mJumpThresholdSquare = Integer.MAX_VALUE; 543e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani /** The y coordinate of the last row */ 553e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani private int mLastRowY; 563f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani 57923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public LatinKeyboardView(Context context, AttributeSet attrs) { 58a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka this(context, attrs, 0); 59923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) { 62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super(context, attrs, defStyle); 63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 64230cd6f7f27300e2688b5e5a22a5361f446b80e7Amith Yamasani 650ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa public void setPhoneKeyboard(LatinKeyboard phoneKeyboard) { 66923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPhoneKeyboard = phoneKeyboard; 67923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 68230cd6f7f27300e2688b5e5a22a5361f446b80e7Amith Yamasani 69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 703a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka public void setPreviewEnabled(boolean previewEnabled) { 710ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa if (getLatinKeyboard() == mPhoneKeyboard) { 723a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka // Phone keyboard never shows popup preview (except language switch). 733a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka super.setPreviewEnabled(false); 743a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka } else { 753a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka super.setPreviewEnabled(previewEnabled); 763a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka } 773a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka } 783a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka 790ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa public void setLatinKeyboard(LatinKeyboard k) { 800fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani super.setKeyboard(k); 810fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // One-seventh of the keyboard width seems like a reasonable threshold 820fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mJumpThresholdSquare = k.getMinWidth() / 7; 830fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mJumpThresholdSquare *= mJumpThresholdSquare; 843e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani // Assuming there are 4 rows, this is the coordinate of the last row 853e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani mLastRowY = (k.getHeight() * 3) / 4; 860fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani setKeyboardLocal(k); 870fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 880fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 890ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa public LatinKeyboard getLatinKeyboard() { 900ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa BaseKeyboard keyboard = getKeyboard(); 910ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa if (keyboard instanceof LatinKeyboard) { 920ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa return (LatinKeyboard)keyboard; 930ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa } else { 940ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa return null; 950ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa } 960ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa } 970ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa 980fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani @Override 99923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project protected boolean onLongPress(Key key) { 100e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka int primaryCode = key.codes[0]; 101e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka if (primaryCode == KEYCODE_OPTIONS) { 102a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka return invokeOnKey(KEYCODE_OPTIONS_LONGPRESS); 1030ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa } else if (primaryCode == '0' && getLatinKeyboard() == mPhoneKeyboard) { 104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Long pressing on 0 in phone number keypad gives you a '+'. 105a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka return invokeOnKey('+'); 106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return super.onLongPress(key); 108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 111a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka private boolean invokeOnKey(int primaryCode) { 112a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka getOnKeyboardActionListener().onKey(primaryCode, null, 113a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE, 114a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE); 115a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka return true; 116a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka } 117a1cc4f0a8d9a70ff1515d1ddb1476f6ce630afe2Tadashi G. Takaoka 118979f8690967ff5409fe18f5085858ccdb8e0ccf1satok @Override 119979f8690967ff5409fe18f5085858ccdb8e0ccf1satok protected CharSequence adjustCase(CharSequence label) { 1200ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa LatinKeyboard keyboard = getLatinKeyboard(); 1210ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa if (keyboard.isAlphaKeyboard() 12266e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka && keyboard.isShifted() 12375c23ced94979a6b3f7c59e95dd46385e9702e2dKen Wakasa && !TextUtils.isEmpty(label) && label.length() < 3 124979f8690967ff5409fe18f5085858ccdb8e0ccf1satok && Character.isLowerCase(label.charAt(0))) { 125979f8690967ff5409fe18f5085858ccdb8e0ccf1satok label = label.toString().toUpperCase(); 126979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 127979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return label; 128979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 129979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 130979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public boolean setShiftLocked(boolean shiftLocked) { 1310ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa LatinKeyboard keyboard = getLatinKeyboard(); 1320ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa keyboard.setShiftLocked(shiftLocked); 1330ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa invalidateAllKeys(); 1340ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa return true; 135979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 136979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1370fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani /** 1380fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * This function checks to see if we need to handle any sudden jumps in the pointer location 1390fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * that could be due to a multi-touch being treated as a move by the firmware or hardware. 1400fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * Once a sudden jump is detected, all subsequent move events are discarded 1410fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * until an UP is received.<P> 142e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka * When a sudden jump is detected, an UP event is simulated at the last position and when 1430fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * the sudden moves subside, a DOWN event is simulated for the second key. 1440fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * @param me the motion event 145e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka * @return true if the event was consumed, so that it doesn't continue to be handled by 1460fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani * KeyboardView. 1470fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani */ 1480fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani private boolean handleSuddenJump(MotionEvent me) { 1490fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int action = me.getAction(); 1500fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int x = (int) me.getX(); 1510fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int y = (int) me.getY(); 1520fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani boolean result = false; 1530fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 1540fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Real multi-touch event? Stop looking for sudden jumps 1550fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (me.getPointerCount() > 1) { 1560fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDisableDisambiguation = true; 1570fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1580fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (mDisableDisambiguation) { 1590fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If UP, reset the multi-touch flag 1600fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (action == MotionEvent.ACTION_UP) mDisableDisambiguation = false; 1610fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani return false; 1620fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1630fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 1640fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani switch (action) { 1650fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_DOWN: 1660fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Reset the "session" 1670fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = false; 1680fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDisableDisambiguation = false; 1690fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 1700fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_MOVE: 1710fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Is this a big jump? 1720fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani final int distanceSquare = (mLastX - x) * (mLastX - x) + (mLastY - y) * (mLastY - y); 1733e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani // Check the distance and also if the move is not entirely within the bottom row 1743e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani // If it's only in the bottom row, it might be an intentional slide gesture 1753e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani // for language switching 1763e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani if (distanceSquare > mJumpThresholdSquare 1773e0c82ec80a69c4adbd60546c3c56c83c43ec7ebAmith Yamasani && (mLastY < mLastRowY || y < mLastRowY)) { 1780fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If we're not yet dropping events, start dropping and send an UP event 1790fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (!mDroppingEvents) { 1800fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = true; 1810fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Send an up event 1820fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), 1830fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent.ACTION_UP, 1840fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastX, mLastY, me.getMetaState()); 1850fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani super.onTouchEvent(translated); 1860fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani translated.recycle(); 1870fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1880fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani result = true; 1890fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } else if (mDroppingEvents) { 1900fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // If moves are small and we're already dropping events, continue dropping 1910fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani result = true; 1920fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 1930fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 1940fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani case MotionEvent.ACTION_UP: 1950fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani if (mDroppingEvents) { 1960fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Send a down event first, as we dropped a bunch of sudden jumps and assume that 1970fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // the user is releasing the touch on the second key. 1980fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), 1990fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani MotionEvent.ACTION_DOWN, 2000fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani x, y, me.getMetaState()); 2010fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani super.onTouchEvent(translated); 2020fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani translated.recycle(); 2030fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mDroppingEvents = false; 2040fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Let the up event get processed as well, result = false 2050fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 2060fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani break; 2070fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 2080fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani // Track the previous coordinate 2090fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastX = x; 2100fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani mLastY = y; 2110fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani return result; 2120fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani } 2130fef498a07515bdd5ac1ccfa564776d72fd85a51Amith Yamasani 214358e485b14938fbcb5af5be75aa29f2b73674100Amith Yamasani @Override 215358e485b14938fbcb5af5be75aa29f2b73674100Amith Yamasani public boolean onTouchEvent(MotionEvent me) { 2160ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa LatinKeyboard keyboard = getLatinKeyboard(); 2171b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani if (DEBUG_LINE) { 2181b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani mLastX = (int) me.getX(); 2191b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani mLastY = (int) me.getY(); 2201b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani invalidate(); 2211b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani } 222938c178215d38c6f085b32b0994598f9e8bc5ab5Amith Yamasani 223d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka // If there was a sudden jump, return without processing the actual motion event. 224d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka if (handleSuddenJump(me)) 225d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka return true; 226d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka 2273f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani // Reset any bounding box controls in the keyboard 2283f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani if (me.getAction() == MotionEvent.ACTION_DOWN) { 2293f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani keyboard.keyReleased(); 2303f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani } 2313f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani 2323f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani if (me.getAction() == MotionEvent.ACTION_UP) { 2333f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani int languageDirection = keyboard.getLanguageChangeDirection(); 2343f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani if (languageDirection != 0) { 2353f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani getOnKeyboardActionListener().onKey( 2363f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani languageDirection == 1 ? KEYCODE_NEXT_LANGUAGE : KEYCODE_PREV_LANGUAGE, 237542f057ef64ae16cf2bc528880cf32bfd073edadsatok null, mLastX, mLastY); 2383f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani me.setAction(MotionEvent.ACTION_CANCEL); 2393f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani keyboard.keyReleased(); 2403f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani return super.onTouchEvent(me); 2413f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani } 2423f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani } 2433f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani 244d2a431efa726771dee5c7b90004a0ed670d9a129Tadashi G. Takaoka return super.onTouchEvent(me); 245bad436e93b49116f9005433845bf53126452a839Amith Yamasani } 246bad436e93b49116f9005433845bf53126452a839Amith Yamasani 247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /**************************** INSTRUMENTATION *******************************/ 248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 249923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project static final boolean DEBUG_AUTO_PLAY = false; 2501b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani static final boolean DEBUG_LINE = false; 251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int MSG_TOUCH_DOWN = 1; 252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int MSG_TOUCH_UP = 2; 253e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka 254923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project Handler mHandler2; 255e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka 256923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private String mStringToPlay; 257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private int mStringIndex; 258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private boolean mDownDelivered; 259923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private Key[] mAsciiKeys = new Key[256]; 260923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private boolean mPlaying; 2611b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani private int mLastX; 2621b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani private int mLastY; 2631b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani private Paint mPaint; 264923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2650ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa private void setKeyboardLocal(LatinKeyboard k) { 266923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (DEBUG_AUTO_PLAY) { 267923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project findKeys(); 268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mHandler2 == null) { 269923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mHandler2 = new Handler() { 270923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 271923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void handleMessage(Message msg) { 272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project removeMessages(MSG_TOUCH_DOWN); 273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project removeMessages(MSG_TOUCH_UP); 274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mPlaying == false) return; 275e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka 276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (msg.what) { 277923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project case MSG_TOUCH_DOWN: 278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mStringIndex >= mStringToPlay.length()) { 279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPlaying = false; 280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 281923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project char c = mStringToPlay.charAt(mStringIndex); 283e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka while (c > 255 || mAsciiKeys[c] == null) { 284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mStringIndex++; 285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mStringIndex >= mStringToPlay.length()) { 286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPlaying = false; 287923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 288923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project c = mStringToPlay.charAt(mStringIndex); 290923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int x = mAsciiKeys[c].x + 10; 292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int y = mAsciiKeys[c].y + 26; 293e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), 294e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka SystemClock.uptimeMillis(), 295923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project MotionEvent.ACTION_DOWN, x, y, 0); 296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project LatinKeyboardView.this.dispatchTouchEvent(me); 297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project me.recycle(); 298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project sendEmptyMessageDelayed(MSG_TOUCH_UP, 500); // Deliver up in 500ms if nothing else 299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // happens 300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mDownDelivered = true; 301923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project break; 302923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project case MSG_TOUCH_UP: 303923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project char cUp = mStringToPlay.charAt(mStringIndex); 304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int x2 = mAsciiKeys[cUp].x + 10; 305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int y2 = mAsciiKeys[cUp].y + 26; 306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mStringIndex++; 307e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka 308e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka MotionEvent me2 = MotionEvent.obtain(SystemClock.uptimeMillis(), 309e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka SystemClock.uptimeMillis(), 310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project MotionEvent.ACTION_UP, x2, y2, 0); 311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project LatinKeyboardView.this.dispatchTouchEvent(me2); 312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project me2.recycle(); 313923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 500); // Deliver up in 500ms if nothing else 314923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // happens 315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mDownDelivered = false; 316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project break; 317923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 318923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project }; 320923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 321923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 322923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 323923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 324923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void findKeys() { 3260ce98cbf98c6409ac18fa341f467703d78352a4cKen Wakasa List<Key> keys = getLatinKeyboard().getKeys(); 327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Get the keys on this keyboard 328923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project for (int i = 0; i < keys.size(); i++) { 329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int code = keys.get(i).codes[0]; 330e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka if (code >= 0 && code <= 255) { 331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mAsciiKeys[code] = keys.get(i); 332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 334923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 335979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 336979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public void startPlaying(String s) { 337979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (DEBUG_AUTO_PLAY) { 338979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (s == null) return; 339979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mStringToPlay = s.toLowerCase(); 340979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mPlaying = true; 341979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mDownDelivered = false; 342979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mStringIndex = 0; 343979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 10); 344979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 345923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 346923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 347923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 348923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void draw(Canvas c) { 349979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinIMEUtil.GCUtils.getInstance().reset(); 350979f8690967ff5409fe18f5085858ccdb8e0ccf1satok boolean tryGC = true; 351979f8690967ff5409fe18f5085858ccdb8e0ccf1satok for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 352979f8690967ff5409fe18f5085858ccdb8e0ccf1satok try { 353979f8690967ff5409fe18f5085858ccdb8e0ccf1satok super.draw(c); 354979f8690967ff5409fe18f5085858ccdb8e0ccf1satok tryGC = false; 355979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } catch (OutOfMemoryError e) { 356979f8690967ff5409fe18f5085858ccdb8e0ccf1satok tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait("LatinKeyboardView", e); 357979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 358979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 359979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (DEBUG_AUTO_PLAY) { 360979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (mPlaying) { 361979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mHandler2.removeMessages(MSG_TOUCH_DOWN); 362979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mHandler2.removeMessages(MSG_TOUCH_UP); 363979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (mDownDelivered) { 364979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_UP, 20); 365979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } else { 366979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 20); 367979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 368923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 3701b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani if (DEBUG_LINE) { 3711b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani if (mPaint == null) { 3721b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani mPaint = new Paint(); 3731b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani mPaint.setColor(0x80FFFFFF); 3741b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani mPaint.setAntiAlias(false); 3751b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani } 3761b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani c.drawLine(mLastX, 0, mLastX, getHeight(), mPaint); 3771b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani c.drawLine(0, mLastY, getWidth(), mLastY, mPaint); 3781b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani } 379923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 380923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 381