19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008-2009 Google Inc. 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * License for the specific language governing permissions and limitations under 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.inputmethodservice; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 21ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Projectimport android.graphics.Bitmap; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint; 24ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Projectimport android.graphics.PorterDuff; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Typeface; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint.Align; 28ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Projectimport android.graphics.Region.Op; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.inputmethodservice.Keyboard.Key; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 34e403700972f0c3187382c35e9b037b9a4907cf52Amith Yamasaniimport android.util.TypedValue; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.GestureDetector; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 40b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasaniimport android.view.ViewConfiguration; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup.LayoutParams; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.PopupWindow; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 45ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Projectimport com.android.internal.R; 46ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A view that renders a virtual {@link Keyboard}. It handles rendering of keys and 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * detecting key presses and touch movements. 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyBackground 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyPreviewLayout 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyPreviewOffset 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_labelTextSize 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyTextSize 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyTextColor 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_verticalCorrection 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_popupLayout 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class KeyboardView extends View implements View.OnClickListener { 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Listener for virtual keyboard events. 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public interface OnKeyboardActionListener { 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user presses a key. This is sent before the {@link #onKey} is called. 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For keys that repeat, this is only called once. 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * key, the value will be zero. 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPress(int primaryCode); 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user releases a key. This is sent after the {@link #onKey} is called. 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For keys that repeat, this is only called once. 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param primaryCode the code of the key that was released 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onRelease(int primaryCode); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Send a key press to the listener. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param primaryCode this is the key that was pressed 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param keyCodes the codes for all the possible alternative keys 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with the primary code being the first. If the primary key code is 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a single character such as an alphabet or number or symbol, the alternatives 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will include other characters that may be on the same key or adjacent keys. 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * These codes are useful to correct for accidental presses of a key adjacent to 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the intended key. 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onKey(int primaryCode, int[] keyCodes); 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sends a sequence of characters to the listener. 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param text the sequence of characters to be displayed. 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onText(CharSequence text); 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user quickly moves the finger from right to left. 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void swipeLeft(); 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user quickly moves the finger from left to right. 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void swipeRight(); 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user quickly moves the finger from up to down. 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void swipeDown(); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user quickly moves the finger from down to up. 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void swipeUp(); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean DEBUG = false; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int NOT_A_KEY = -1; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE }; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int[] LONG_PRESSABLE_STATE_SET = { R.attr.state_long_pressable }; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Keyboard mKeyboard; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mCurrentKeyIndex = NOT_A_KEY; 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLabelTextSize; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mKeyTextSize; 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mKeyTextColor; 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mShadowRadius; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mShadowColor; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mBackgroundDimAmount; 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextView mPreviewText; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PopupWindow mPreviewPopup; 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPreviewTextSizeLarge; 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPreviewOffset; 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPreviewHeight; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mOffsetInWindow; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PopupWindow mPopupKeyboard; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View mMiniKeyboardContainer; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private KeyboardView mMiniKeyboard; 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mMiniKeyboardOnScreen; 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View mPopupParent; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMiniKeyboardOffsetX; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMiniKeyboardOffsetY; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Map<Key,View> mMiniKeyboardCache; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mWindowOffset; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Key[] mKeys; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Listener for {@link OnKeyboardActionListener}. */ 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnKeyboardActionListener mKeyboardActionListener; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_SHOW_PREVIEW = 1; 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_REMOVE_PREVIEW = 2; 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_REPEAT = 3; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_LONGPRESS = 4; 165e403700972f0c3187382c35e9b037b9a4907cf52Amith Yamasani 16629d85df051ca5e888a8f2b42416d09fc931d1a75Amith Yamasani private static final int DELAY_BEFORE_PREVIEW = 0; 16729d85df051ca5e888a8f2b42416d09fc931d1a75Amith Yamasani private static final int DELAY_AFTER_PREVIEW = 70; 1687aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani private static final int DEBOUNCE_TIME = 70; 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVerticalCorrection; 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mProximityThreshold; 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mPreviewCentered = false; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mShowPreview = true; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mShowTouchPoints = true; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupPreviewX; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupPreviewY; 17842973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani private int mWindowY; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastX; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastY; 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mStartX; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mStartY; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mProximityCorrectOn; 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Paint mPaint; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Rect mPadding; 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mDownTime; 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastMoveTime; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastKey; 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastCodeX; 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastCodeY; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mCurrentKey = NOT_A_KEY; 196aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private int mDownKey = NOT_A_KEY; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastKeyTime; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mCurrentKeyTime; 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mKeyIndices = new int[12]; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private GestureDetector mGestureDetector; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupX; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupY; 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mRepeatKeyIndex = NOT_A_KEY; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupLayout; 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mAbortKey; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Key mInvalidatedKey; 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Rect mClipRegion = new Rect(0, 0, 0, 0); 208aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private boolean mPossiblePoly; 209aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private SwipeTracker mSwipeTracker = new SwipeTracker(); 210aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private int mSwipeThreshold; 211aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private boolean mDisambiguateSwipe; 212e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 213e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Variables for dealing with multiple pointers 214e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani private int mOldPointerCount = 1; 215e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani private float mOldPointerX; 216e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani private float mOldPointerY; 217e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Drawable mKeyBackground; 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int REPEAT_INTERVAL = 50; // ~20 keys per second 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int REPEAT_START_DELAY = 400; 222b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasani private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int MAX_NEARBY_KEYS = 12; 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mDistances = new int[MAX_NEARBY_KEYS]; 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For multi-tap 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastSentIndex; 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTapCount; 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastTapTime; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInMultiTap; 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MULTITAP_INTERVAL = 800; // milliseconds 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private StringBuilder mPreviewLabel = new StringBuilder(1); 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 235ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/ 236ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private boolean mDrawPending; 237ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project /** The dirty region in the keyboard bitmap */ 238ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private Rect mDirtyRect = new Rect(); 239ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project /** The keyboard bitmap for faster updates */ 240ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private Bitmap mBuffer; 241e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */ 242e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani private boolean mKeyboardChanged; 243ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project /** The canvas for the above mutable keyboard bitmap */ 244ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private Canvas mCanvas; 245ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Handler mHandler = new Handler() { 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleMessage(Message msg) { 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (msg.what) { 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_SHOW_PREVIEW: 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showKey(msg.arg1); 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_REMOVE_PREVIEW: 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setVisibility(INVISIBLE); 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_REPEAT: 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (repeatKey()) { 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message repeat = Message.obtain(this, MSG_REPEAT); 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sendMessageDelayed(repeat, REPEAT_INTERVAL); 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_LONGPRESS: 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project openPopupIfRequired((MotionEvent) msg.obj); 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public KeyboardView(Context context, AttributeSet attrs) { 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, attrs, com.android.internal.R.attr.keyboardViewStyle); 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public KeyboardView(Context context, AttributeSet attrs, int defStyle) { 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs, defStyle); 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TypedArray a = 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project context.obtainStyledAttributes( 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attrs, android.R.styleable.KeyboardView, defStyle, 0); 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LayoutInflater inflate = 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (LayoutInflater) context 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int previewLayout = 0; 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int keyTextSize = 0; 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int n = a.getIndexCount(); 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < n; i++) { 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int attr = a.getIndex(i); 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (attr) { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyBackground: 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyBackground = a.getDrawable(attr); 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_verticalCorrection: 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVerticalCorrection = a.getDimensionPixelOffset(attr, 0); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyPreviewLayout: 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previewLayout = a.getResourceId(attr, 0); 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyPreviewOffset: 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewOffset = a.getDimensionPixelOffset(attr, 0); 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyPreviewHeight: 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewHeight = a.getDimensionPixelSize(attr, 80); 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyTextSize: 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyTextSize = a.getDimensionPixelSize(attr, 18); 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyTextColor: 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyTextColor = a.getColor(attr, 0xFF000000); 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_labelTextSize: 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLabelTextSize = a.getDimensionPixelSize(attr, 14); 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_popupLayout: 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupLayout = a.getResourceId(attr, 0); 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_shadowColor: 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShadowColor = a.getColor(attr, 0); 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_shadowRadius: 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShadowRadius = a.getFloat(attr, 0f); 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project a = mContext.obtainStyledAttributes( 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.styleable.Theme); 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBackgroundDimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f); 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup = new PopupWindow(context); 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previewLayout != 0) { 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText = (TextView) inflate.inflate(previewLayout, null); 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewTextSizeLarge = (int) mPreviewText.getTextSize(); 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShowPreview = false; 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.setTouchable(false); 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard = new PopupWindow(context); 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.setBackgroundDrawable(null); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mPopupKeyboard.setClippingEnabled(false); 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupParent = this; 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mPredicting = true; 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint = new Paint(); 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setAntiAlias(true); 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setTextSize(keyTextSize); 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setTextAlign(Align.CENTER); 356e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mPaint.setAlpha(255); 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPadding = new Rect(0, 0, 0, 0); 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardCache = new HashMap<Key,View>(); 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyBackground.getPadding(mPadding); 361aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 362aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density); 363aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mDisambiguateSwipe = getResources().getBoolean( 364aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani com.android.internal.R.bool.config_swipeDisambiguation); 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMultiTap(); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initGestureDetector(); 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void initGestureDetector() { 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onFling(MotionEvent me1, MotionEvent me2, 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float velocityX, float velocityY) { 374aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (mPossiblePoly) return false; 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float absX = Math.abs(velocityX); 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final float absY = Math.abs(velocityY); 377aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float deltaX = me2.getX() - me1.getX(); 378aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float deltaY = me2.getY() - me1.getY(); 379aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani int travelX = getWidth() / 2; // Half the keyboard width 380aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani int travelY = getHeight() / 2; // Half the keyboard height 381aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mSwipeTracker.computeCurrentVelocity(1000); 382aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float endingVelocityX = mSwipeTracker.getXVelocity(); 383aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float endingVelocityY = mSwipeTracker.getYVelocity(); 384aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani boolean sendDownKey = false; 385aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) { 386aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) { 387aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani sendDownKey = true; 388aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else { 389aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani swipeRight(); 390aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani return true; 391aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 392aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) { 393aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) { 394aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani sendDownKey = true; 395aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else { 396aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani swipeLeft(); 397aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani return true; 398aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 399aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) { 400aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) { 401aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani sendDownKey = true; 402aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else { 403aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani swipeUp(); 404aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani return true; 405aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 406aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) { 407aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) { 408aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani sendDownKey = true; 409aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else { 410aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani swipeDown(); 411aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani return true; 412aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 413aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 414aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 415aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (sendDownKey) { 416aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime()); 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGestureDetector.setIsLongpressEnabled(false); 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener = listener; 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the {@link OnKeyboardActionListener} object. 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the listener attached to this keyboard 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected OnKeyboardActionListener getOnKeyboardActionListener() { 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mKeyboardActionListener; 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Attaches a keyboard to this view. The keyboard can be switched at any time and the 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * view will re-layout itself to accommodate the keyboard. 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Keyboard 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getKeyboard() 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param keyboard the keyboard to display in this view 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setKeyboard(Keyboard keyboard) { 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard != null) { 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(NOT_A_KEY); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 448ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani // Remove any pending messages 449ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani removeMessages(); 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboard = keyboard; 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<Key> keys = mKeyboard.getKeys(); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeys = keys.toArray(new Key[keys.size()]); 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 454e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Hint to reallocate the buffer if the size changed 455e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mKeyboardChanged = true; 456f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project computeProximityThreshold(keyboard); 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views 459b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasani // Switching to a different keyboard should abort any pending keys so that the key up 460b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasani // doesn't get delivered to the old or new keyboard 461b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasani mAbortKey = true; // Until the next ACTION_DOWN 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the current keyboard being displayed by this view. 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the currently attached keyboard 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setKeyboard(Keyboard) 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Keyboard getKeyboard() { 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mKeyboard; 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the state of the shift key of the keyboard, if any. 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param shifted whether or not to enable the state of the shift key 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the shift key state changed, false if there was no change 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see KeyboardView#isShifted() 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean setShifted(boolean shifted) { 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard != null) { 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard.setShifted(shifted)) { 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The whole keyboard probably needs to be redrawn 483f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the state of the shift key of the keyboard, if any. 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the shift is in a pressed state, false otherwise. If there is 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * no shift key on the keyboard or there is no keyboard attached, it returns false. 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see KeyboardView#setShifted(boolean) 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isShifted() { 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard != null) { 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mKeyboard.isShifted(); 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables the key feedback popup. This is a popup that shows a magnified 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * version of the depressed key. By default the preview is enabled. 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param previewEnabled whether or not to enable the key feedback popup 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #isPreviewEnabled() 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPreviewEnabled(boolean previewEnabled) { 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShowPreview = previewEnabled; 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the enabled state of the key feedback popup. 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return whether or not the key feedback popup is enabled 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setPreviewEnabled(boolean) 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isPreviewEnabled() { 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mShowPreview; 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVerticalCorrection(int verticalOffset) { 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPopupParent(View v) { 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupParent = v; 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPopupOffset(int x, int y) { 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardOffsetX = x; 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardOffsetY = y; 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPreviewPopup.isShowing()) { 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.dismiss(); 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 538f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * When enabled, calls to {@link OnKeyboardActionListener#onKey} will include key 539f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * codes for adjacent keys. When disabled, only the primary key code will be 540f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * reported. 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param enabled whether or not the proximity correction is enabled 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setProximityCorrectionEnabled(boolean enabled) { 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProximityCorrectOn = enabled; 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 548f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * Returns true if proximity correction is enabled. 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isProximityCorrectionEnabled() { 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mProximityCorrectOn; 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Popup keyboard close button clicked. 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onClick(View v) { 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private CharSequence adjustCase(CharSequence label) { 5634df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project if (mKeyboard.isShifted() && label != null && label.length() < 3 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && Character.isLowerCase(label.charAt(0))) { 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project label = label.toString().toUpperCase(); 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return label; 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Round up a little 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard == null) { 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setMeasuredDimension(mPaddingLeft + mPaddingRight, mPaddingTop + mPaddingBottom); 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width = mKeyboard.getMinWidth() + mPaddingLeft + mPaddingRight; 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) { 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project width = MeasureSpec.getSize(widthMeasureSpec); 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setMeasuredDimension(width, mKeyboard.getHeight() + mPaddingTop + mPaddingBottom); 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compute the average distance between adjacent keys (horizontally and vertically) 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and square it to get the proximity threshold. We use a square here and in computing 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the touch distance from a key's center to avoid taking a square root. 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param keyboard 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void computeProximityThreshold(Keyboard keyboard) { 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyboard == null) return; 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keys == null) return; 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = keys.length; 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dimensionSum = 0; 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < length; i++) { 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key key = keys[i]; 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dimensionSum += Math.min(key.width, key.height) + key.gap; 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dimensionSum < 0 || length == 0) return; 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProximityThreshold = (int) (dimensionSum * 1.4f / length); 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProximityThreshold *= mProximityThreshold; // Square it 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 606ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project public void onSizeChanged(int w, int h, int oldw, int oldh) { 607ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project super.onSizeChanged(w, h, oldw, oldh); 608ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project // Release the buffer, if any and it will be reallocated on the next draw 609ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mBuffer = null; 610ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 611ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 612ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project @Override 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onDraw(Canvas canvas) { 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onDraw(canvas); 615e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (mDrawPending || mBuffer == null || mKeyboardChanged) { 616ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project onBufferDraw(); 617ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 618ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project canvas.drawBitmap(mBuffer, 0, 0, null); 619ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 620e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 621ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private void onBufferDraw() { 622e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (mBuffer == null || mKeyboardChanged) { 623e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (mBuffer == null || mKeyboardChanged && 624e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) { 62546a61bb730e1f144511be49722af573aba73edbaRomain Guy // Make sure our bitmap is at least 1x1 62646a61bb730e1f144511be49722af573aba73edbaRomain Guy final int width = Math.max(1, getWidth()); 62746a61bb730e1f144511be49722af573aba73edbaRomain Guy final int height = Math.max(1, getHeight()); 62846a61bb730e1f144511be49722af573aba73edbaRomain Guy mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 629e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mCanvas = new Canvas(mBuffer); 630e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 631f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 632e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mKeyboardChanged = false; 633ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 634ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project final Canvas canvas = mCanvas; 635ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project canvas.clipRect(mDirtyRect, Op.REPLACE); 636ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard == null) return; 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Paint paint = mPaint; 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Drawable keyBackground = mKeyBackground; 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Rect clipRegion = mClipRegion; 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Rect padding = mPadding; 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int kbdPaddingLeft = mPaddingLeft; 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int kbdPaddingTop = mPaddingTop; 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key invalidKey = mInvalidatedKey; 647ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor(mKeyTextColor); 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean drawSingleKey = false; 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (invalidKey != null && canvas.getClipBounds(clipRegion)) { 651ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project // Is clipRegion completely contained within the invalidated key? 652ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left && 653ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top && 654ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right && 655ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) { 656ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project drawSingleKey = true; 657ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 659ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int keyCount = keys.length; 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < keyCount; i++) { 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key key = keys[i]; 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (drawSingleKey && invalidKey != key) { 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] drawableState = key.getCurrentDrawableState(); 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyBackground.setState(drawableState); 668e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Switch the character to uppercase if shift is pressed 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String label = key.label == null? null : adjustCase(key.label).toString(); 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Rect bounds = keyBackground.getBounds(); 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.width != bounds.right || 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.height != bounds.bottom) { 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyBackground.setBounds(0, 0, key.width, key.height); 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop); 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyBackground.draw(canvas); 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (label != null) { 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For characters, use large font. For labels like "Done", use small font. 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (label.length() > 1 && key.codes.length < 2) { 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setTextSize(mLabelTextSize); 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setTypeface(Typeface.DEFAULT_BOLD); 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setTextSize(mKeyTextSize); 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setTypeface(Typeface.DEFAULT); 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Draw a drop shadow for the text 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Draw the text 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawText(label, 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (key.width - padding.left - padding.right) / 2 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + padding.left, 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (key.height - padding.top - padding.bottom) / 2 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (paint.getTextSize() - paint.descent()) / 2 + padding.top, 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint); 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Turn off drop shadow 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setShadowLayer(0, 0, 0, 0); 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (key.icon != null) { 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int drawableX = (key.width - padding.left - padding.right 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project - key.icon.getIntrinsicWidth()) / 2 + padding.left; 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int drawableY = (key.height - padding.top - padding.bottom 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project - key.icon.getIntrinsicHeight()) / 2 + padding.top; 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(drawableX, drawableY); 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.icon.setBounds(0, 0, 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight()); 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.icon.draw(canvas); 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(-drawableX, -drawableY); 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop); 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInvalidatedKey = null; 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Overlay a dark rectangle to dim the keyboard 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMiniKeyboardOnScreen) { 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawRect(0, 0, getWidth(), getHeight(), paint); 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DEBUG && mShowTouchPoints) { 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setAlpha(128); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor(0xFFFF0000); 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawCircle(mStartX, mStartY, 3, paint); 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawLine(mStartX, mStartY, mLastX, mLastY, paint); 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor(0xFF0000FF); 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawCircle(mLastX, mLastY, 3, paint); 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor(0xFF00FF00); 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint); 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 730ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 731ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDrawPending = false; 732ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDirtyRect.setEmpty(); 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getKeyIndices(int x, int y, int[] allKeys) { 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int primaryIndex = NOT_A_KEY; 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int closestKey = NOT_A_KEY; 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int closestKeyDist = mProximityThreshold + 1; 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project java.util.Arrays.fill(mDistances, Integer.MAX_VALUE); 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int keyCount = nearestKeyIndices.length; 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < keyCount; i++) { 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key key = keys[nearestKeyIndices[i]]; 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dist = 0; 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean isInside = key.isInside(x,y); 747ec5df83c5b44ad2f2b28a1a4420c4c4056dd6103Amith Yamasani if (isInside) { 748ec5df83c5b44ad2f2b28a1a4420c4c4056dd6103Amith Yamasani primaryIndex = nearestKeyIndices[i]; 749ec5df83c5b44ad2f2b28a1a4420c4c4056dd6103Amith Yamasani } 750ec5df83c5b44ad2f2b28a1a4420c4c4056dd6103Amith Yamasani 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (((mProximityCorrectOn 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold) 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || isInside) 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && key.codes[0] > 32) { 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find insertion point 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int nCodes = key.codes.length; 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dist < closestKeyDist) { 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closestKeyDist = dist; 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closestKey = nearestKeyIndices[i]; 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (allKeys == null) continue; 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mDistances.length; j++) { 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDistances[j] > dist) { 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make space for nCodes codes 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(mDistances, j, mDistances, j + nCodes, 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDistances.length - j - nCodes); 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(allKeys, j, allKeys, j + nCodes, 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project allKeys.length - j - nCodes); 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int c = 0; c < nCodes; c++) { 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project allKeys[j + c] = key.codes[c]; 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDistances[j + c] = dist; 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (primaryIndex == NOT_A_KEY) { 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project primaryIndex = closestKey; 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return primaryIndex; 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 786aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private void detectAndSendKey(int index, int x, int y, long eventTime) { 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (index != NOT_A_KEY && index < mKeys.length) { 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key key = mKeys[index]; 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.text != null) { 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onText(key.text); 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onRelease(NOT_A_KEY); 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int code = key.codes[0]; 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //TextEntryState.keyPressedAt(key, x, y); 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] codes = new int[MAX_NEARBY_KEYS]; 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Arrays.fill(codes, NOT_A_KEY); 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getKeyIndices(x, y, codes); 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Multi-tap 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInMultiTap) { 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mTapCount != -1) { 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE); 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTapCount = 0; 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project code = key.codes[mTapCount]; 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onKey(code, codes); 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onRelease(code); 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastSentIndex = index; 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastTapTime = eventTime; 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handle multi-tap keys by producing the key label for the current multi-tap state. 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private CharSequence getPreviewText(Key key) { 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInMultiTap) { 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Multi-tap 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewLabel.setLength(0); 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]); 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return adjustCase(mPreviewLabel); 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return adjustCase(key.label); 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void showPreview(int keyIndex) { 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldKeyIndex = mCurrentKeyIndex; 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final PopupWindow previewPopup = mPreviewPopup; 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyIndex = keyIndex; 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Release the old key and press the new key 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldKeyIndex != mCurrentKeyIndex) { 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) { 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keys[oldKeyIndex].onReleased(mCurrentKeyIndex == NOT_A_KEY); 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidateKey(oldKeyIndex); 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) { 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keys[mCurrentKeyIndex].onPressed(); 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidateKey(mCurrentKeyIndex); 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If key changed and preview is on ... 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldKeyIndex != mCurrentKeyIndex && mShowPreview) { 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeMessages(MSG_SHOW_PREVIEW); 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previewPopup.isShowing()) { 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex == NOT_A_KEY) { 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed(mHandler 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .obtainMessage(MSG_REMOVE_PREVIEW), 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DELAY_AFTER_PREVIEW); 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex != NOT_A_KEY) { 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Show right away, if it's already visible and finger is moving around 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showKey(keyIndex); 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed( 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0), 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DELAY_BEFORE_PREVIEW); 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void showKey(final int keyIndex) { 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final PopupWindow previewPopup = mPreviewPopup; 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 872ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani if (keyIndex < 0 || keyIndex >= mKeys.length) return; 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key key = keys[keyIndex]; 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.icon != null) { 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setCompoundDrawables(null, null, null, 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.iconPreview != null ? key.iconPreview : key.icon); 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setText(null); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setCompoundDrawables(null, null, null, null); 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setText(getPreviewText(key)); 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.label.length() > 1 && key.codes.length < 2) { 882e403700972f0c3187382c35e9b037b9a4907cf52Amith Yamasani mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize); 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 885e403700972f0c3187382c35e9b037b9a4907cf52Amith Yamasani mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge); 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setTypeface(Typeface.DEFAULT); 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int popupHeight = mPreviewHeight; 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LayoutParams lp = mPreviewText.getLayoutParams(); 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lp != null) { 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lp.width = popupWidth; 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lp.height = popupHeight; 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mPreviewCentered) { 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft; 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupPreviewY = key.y - popupHeight + mPreviewOffset; 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Fix this if centering is brought back 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2; 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupPreviewY = - mPreviewText.getMeasuredHeight(); 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeMessages(MSG_REMOVE_PREVIEW); 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOffsetInWindow == null) { 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOffsetInWindow = new int[2]; 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getLocationInWindow(mOffsetInWindow); 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero 91342973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani int[] mWindowLocation = new int[2]; 91442973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani getLocationOnScreen(mWindowLocation); 91542973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mWindowY = mWindowLocation[1]; 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set the preview background state 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.getBackground().setState( 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); 92042973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewX += mOffsetInWindow[0]; 92142973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewY += mOffsetInWindow[1]; 92242973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani 92342973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani // If the popup cannot be shown above the key, put it on the side 92442973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani if (mPopupPreviewY + mWindowY < 0) { 92542973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani // If the key you're pressing is on the left side of the keyboard, show the popup on 92642973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani // the right, offset by enough to see at least one key to the left/right. 92742973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani if (key.x + key.width <= getWidth() / 2) { 92842973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewX += (int) (key.width * 2.5); 92942973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani } else { 93042973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewX -= (int) (key.width * 2.5); 93142973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani } 93242973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewY += popupHeight; 93342973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani } 93442973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previewPopup.isShowing()) { 93642973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani previewPopup.update(mPopupPreviewX, mPopupPreviewY, 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project popupWidth, popupHeight); 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previewPopup.setWidth(popupWidth); 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previewPopup.setHeight(popupHeight); 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, 94242973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewX, mPopupPreviewY); 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setVisibility(VISIBLE); 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 947f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani /** 948f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient 949f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * because the keyboard renders the keys to an off-screen buffer and an invalidate() only 950f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * draws the cached buffer. 951f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * @see #invalidateKey(int) 952f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani */ 953f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani public void invalidateAllKeys() { 954ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDirtyRect.union(0, 0, getWidth(), getHeight()); 955ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDrawPending = true; 956ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidate(); 957ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 958f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani 959f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani /** 960f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * Invalidates a key so that it will be redrawn on the next repaint. Use this method if only 961f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * one key is changing it's content. Any changes that affect the position or size of the key 962f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * may not be honored. 963f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * @param keyIndex the index of the key in the attached {@link Keyboard}. 964f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * @see #invalidateAllKeys 965f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani */ 966f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani public void invalidateKey(int keyIndex) { 967f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani if (mKeys == null) return; 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex < 0 || keyIndex >= mKeys.length) { 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key key = mKeys[keyIndex]; 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInvalidatedKey = key; 973ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDirtyRect.union(key.x + mPaddingLeft, key.y + mPaddingTop, 974ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop); 975ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project onBufferDraw(); 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(key.x + mPaddingLeft, key.y + mPaddingTop, 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop); 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean openPopupIfRequired(MotionEvent me) { 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check if we have a popup layout specified first. 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPopupLayout == 0) { 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKey < 0 || mCurrentKey >= mKeys.length) { 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key popupKey = mKeys[mCurrentKey]; 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean result = onLongPress(popupKey); 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result) { 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAbortKey = true; 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(NOT_A_KEY); 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when a key is long pressed. By default this will open any popup keyboard associated 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with this key through the attributes popupLayout and popupCharacters. 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param popupKey the key that was long pressed 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the long press is handled, false otherwise. Subclasses should call the 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * method on the base class if the subclass doesn't wish to handle the call. 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected boolean onLongPress(Key popupKey) { 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int popupKeyboardId = popupKey.popupResId; 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (popupKeyboardId != 0) { 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey); 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMiniKeyboardContainer == null) { 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Context.LAYOUT_INFLATER_SERVICE); 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null); 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById( 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.id.keyboardView); 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View closeButton = mMiniKeyboardContainer.findViewById( 101788fb1069bf254dc68c83546496592a9b5e739a07Dianne Hackborn com.android.internal.R.id.closeButton); 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (closeButton != null) closeButton.setOnClickListener(this); 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onKey(int primaryCode, int[] keyCodes) { 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onKey(primaryCode, keyCodes); 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onText(CharSequence text) { 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onText(text); 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void swipeLeft() { } 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void swipeRight() { } 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void swipeUp() { } 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void swipeDown() { } 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onPress(int primaryCode) { 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onPress(primaryCode); 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onRelease(int primaryCode) { 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onRelease(primaryCode); 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mInputView.setSuggest(mSuggest); 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Keyboard keyboard; 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (popupKey.popupCharacters != null) { 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyboard = new Keyboard(getContext(), popupKeyboardId, 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight()); 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyboard = new Keyboard(getContext(), popupKeyboardId); 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setKeyboard(keyboard); 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setPopupParent(this); 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardContainer.measure( 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer); 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById( 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.id.keyboardView); 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mWindowOffset == null) { 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWindowOffset = new int[2]; 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getLocationInWindow(mWindowOffset); 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupX = popupKey.x + mPaddingLeft; 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupY = popupKey.y + mPaddingTop; 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth(); 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight(); 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mWindowOffset[0]; 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mWindowOffset[1]; 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y); 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setShifted(isShifted()); 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.setContentView(mMiniKeyboardContainer); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth()); 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight()); 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y); 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardOnScreen = true; 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me)); 1078f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1083e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 1084aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private long mOldEventTime; 1085aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private boolean mUsedVelocity; 1086aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onTouchEvent(MotionEvent me) { 1089e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Convert multi-pointer up/down events to single up/down events to 1090e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // deal with the typical multi-pointer behavior of two-thumb typing 1091aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int pointerCount = me.getPointerCount(); 1092aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int action = me.getAction(); 1093e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani boolean result = false; 1094aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long now = me.getEventTime(); 1095aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1096e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (pointerCount != mOldPointerCount) { 1097e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (pointerCount == 1) { 1098e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Send a down event for the latest pointer 1099e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 1100e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani me.getX(), me.getY(), me.getMetaState()); 1101aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani result = onModifiedTouchEvent(down, false); 1102e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani down.recycle(); 11038b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani // If it's an up action, then deliver the up as well. 1104aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (action == MotionEvent.ACTION_UP) { 1105aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani result = onModifiedTouchEvent(me, true); 11068b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani } 1107e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } else { 1108e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Send an up event for the last pointer 1109e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1110e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mOldPointerX, mOldPointerY, me.getMetaState()); 1111aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani result = onModifiedTouchEvent(up, true); 1112e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani up.recycle(); 1113e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 1114e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } else { 1115e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (pointerCount == 1) { 1116aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani result = onModifiedTouchEvent(me, false); 1117e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mOldPointerX = me.getX(); 1118e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mOldPointerY = me.getY(); 1119e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } else { 1120e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Don't do anything when 2 pointers are down and moving. 1121e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani result = true; 1122e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 1123e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 1124e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mOldPointerCount = pointerCount; 1125aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1126e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani return result; 1127e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 1128e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 1129aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private boolean onModifiedTouchEvent(MotionEvent me, boolean possiblePoly) { 1130678cdbe55e0de71436f8aad5f139eafc2ab6f937Amith Yamasani int touchX = (int) me.getX() - mPaddingLeft; 1131678cdbe55e0de71436f8aad5f139eafc2ab6f937Amith Yamasani int touchY = (int) me.getY() + mVerticalCorrection - mPaddingTop; 1132aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int action = me.getAction(); 1133aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long eventTime = me.getEventTime(); 1134aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mOldEventTime = eventTime; 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int keyIndex = getKeyIndices(touchX, touchY, null); 1136aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mPossiblePoly = possiblePoly; 1137aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1138aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani // Track the last few movements to look for spurious swipes. 1139aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (action == MotionEvent.ACTION_DOWN) mSwipeTracker.clear(); 1140aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mSwipeTracker.addMovement(me); 1141aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 11424d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani // Ignore all motion events until a DOWN. 11437aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani if (mAbortKey 11447aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) { 11454d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani return true; 11464d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani } 11474d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mGestureDetector.onTouchEvent(me)) { 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(NOT_A_KEY); 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeMessages(MSG_REPEAT); 11518b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani mHandler.removeMessages(MSG_LONGPRESS); 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Needs to be called after the gesture detector gets a turn, as it may have 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // displayed the mini keyboard 11570743a389e8fd1e696c2c02e22689b2d6f12dc48bAmith Yamasani if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) { 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (action) { 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_DOWN: 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAbortKey = false; 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStartX = touchX; 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStartY = touchY; 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastCodeX = touchX; 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastCodeY = touchY; 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKeyTime = 0; 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime = 0; 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKey = NOT_A_KEY; 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = keyIndex; 1172aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mDownKey = keyIndex; 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDownTime = me.getEventTime(); 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastMoveTime = mDownTime; 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkMultiTap(eventTime, keyIndex); 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ? 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeys[keyIndex].codes[0] : 0); 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) { 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRepeatKeyIndex = mCurrentKey; 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message msg = mHandler.obtainMessage(MSG_REPEAT); 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY); 11824d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani repeatKey(); 11834d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani // Delivering the key could have caused an abort 11844d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani if (mAbortKey) { 11854d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani mRepeatKeyIndex = NOT_A_KEY; 11864d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani break; 11874d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani } 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKey != NOT_A_KEY) { 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me); 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT); 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(keyIndex); 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_MOVE: 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean continueLongPress = false; 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex != NOT_A_KEY) { 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKey == NOT_A_KEY) { 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = keyIndex; 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime = eventTime - mDownTime; 12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex == mCurrentKey) { 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime += eventTime - mLastMoveTime; 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continueLongPress = true; 12068b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani } else if (mRepeatKeyIndex == NOT_A_KEY) { 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMultiTap(); 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKey = mCurrentKey; 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastCodeX = mLastX; 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastCodeY = mLastY; 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKeyTime = 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime + eventTime - mLastMoveTime; 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = keyIndex; 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime = 0; 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!continueLongPress) { 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Cancel old longpress 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeMessages(MSG_LONGPRESS); 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Start new longpress if key has changed 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex != NOT_A_KEY) { 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me); 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT); 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12278b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani showPreview(mCurrentKey); 12287aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani mLastMoveTime = eventTime; 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_UP: 1232ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani removeMessages(); 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex == mCurrentKey) { 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime += eventTime - mLastMoveTime; 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMultiTap(); 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKey = mCurrentKey; 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime; 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = keyIndex; 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime = 0; 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12427aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani if (mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < DEBOUNCE_TIME 12437aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani && mLastKey != NOT_A_KEY) { 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = mLastKey; 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project touchX = mLastCodeX; 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project touchY = mLastCodeY; 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(NOT_A_KEY); 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Arrays.fill(mKeyIndices, NOT_A_KEY); 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If we're not on a repeating key (which sends on a DOWN event) 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) { 1252aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani detectAndSendKey(mCurrentKey, touchX, touchY, eventTime); 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1254ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidateKey(keyIndex); 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRepeatKeyIndex = NOT_A_KEY; 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1257aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani case MotionEvent.ACTION_CANCEL: 1258aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani removeMessages(); 12590743a389e8fd1e696c2c02e22689b2d6f12dc48bAmith Yamasani dismissPopupKeyboard(); 1260aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mAbortKey = true; 1261aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani showPreview(NOT_A_KEY); 1262aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani invalidateKey(mCurrentKey); 1263aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani break; 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastX = touchX; 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastY = touchY; 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean repeatKey() { 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key key = mKeys[mRepeatKeyIndex]; 1272aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime); 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void swipeRight() { 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.swipeRight(); 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void swipeLeft() { 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.swipeLeft(); 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void swipeUp() { 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.swipeUp(); 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void swipeDown() { 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.swipeDown(); 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void closing() { 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPreviewPopup.isShowing()) { 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.dismiss(); 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1296ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani removeMessages(); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 1299ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mBuffer = null; 1300ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mCanvas = null; 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardCache.clear(); 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1303ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani 1304ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani private void removeMessages() { 1305ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani mHandler.removeMessages(MSG_REPEAT); 1306ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani mHandler.removeMessages(MSG_LONGPRESS); 1307ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani mHandler.removeMessages(MSG_SHOW_PREVIEW); 1308ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani } 1309ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onDetachedFromWindow() { 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onDetachedFromWindow(); 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closing(); 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void dismissPopupKeyboard() { 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPopupKeyboard.isShowing()) { 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.dismiss(); 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardOnScreen = false; 1320f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1323ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean handleBack() { 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPopupKeyboard.isShowing()) { 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void resetMultiTap() { 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastSentIndex = NOT_A_KEY; 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTapCount = 0; 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastTapTime = -1; 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInMultiTap = false; 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void checkMultiTap(long eventTime, int keyIndex) { 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex == NOT_A_KEY) return; 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key key = mKeys[keyIndex]; 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.codes.length > 1) { 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInMultiTap = true; 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (eventTime < mLastTapTime + MULTITAP_INTERVAL 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && keyIndex == mLastSentIndex) { 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTapCount = (mTapCount + 1) % key.codes.length; 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTapCount = -1; 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) { 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMultiTap(); 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1357aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1358aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private static class SwipeTracker { 1359aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1360aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani static final int NUM_PAST = 4; 1361aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani static final int LONGEST_PAST_TIME = 200; 1362aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1363aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float mPastX[] = new float[NUM_PAST]; 1364aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float mPastY[] = new float[NUM_PAST]; 1365aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long mPastTime[] = new long[NUM_PAST]; 1366aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1367aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float mYVelocity; 1368aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float mXVelocity; 1369aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1370aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public void clear() { 1371aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mPastTime[0] = 0; 1372aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1373aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1374aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public void addMovement(MotionEvent ev) { 1375aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani long time = ev.getEventTime(); 1376aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int N = ev.getHistorySize(); 1377aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani for (int i=0; i<N; i++) { 1378aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i), 1379aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani ev.getHistoricalEventTime(i)); 1380aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1381aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani addPoint(ev.getX(), ev.getY(), time); 1382aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1383aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1384aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private void addPoint(float x, float y, long time) { 1385aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani int drop = -1; 1386aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani int i; 1387aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long[] pastTime = mPastTime; 1388aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani for (i=0; i<NUM_PAST; i++) { 1389aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (pastTime[i] == 0) { 1390aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani break; 1391aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else if (pastTime[i] < time-LONGEST_PAST_TIME) { 1392aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani drop = i; 1393aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1394aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1395aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (i == NUM_PAST && drop < 0) { 1396aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani drop = 0; 1397aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1398aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (drop == i) drop--; 1399aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float[] pastX = mPastX; 1400aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float[] pastY = mPastY; 1401aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (drop >= 0) { 1402aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int start = drop+1; 1403aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int count = NUM_PAST-drop-1; 1404aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani System.arraycopy(pastX, start, pastX, 0, count); 1405aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani System.arraycopy(pastY, start, pastY, 0, count); 1406aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani System.arraycopy(pastTime, start, pastTime, 0, count); 1407aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani i -= (drop+1); 1408aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1409aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani pastX[i] = x; 1410aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani pastY[i] = y; 1411aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani pastTime[i] = time; 1412aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani i++; 1413aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (i < NUM_PAST) { 1414aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani pastTime[i] = 0; 1415aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1416aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1417aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1418aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public void computeCurrentVelocity(int units) { 1419aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani computeCurrentVelocity(units, Float.MAX_VALUE); 1420aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1421aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1422aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public void computeCurrentVelocity(int units, float maxVelocity) { 1423aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float[] pastX = mPastX; 1424aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float[] pastY = mPastY; 1425aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long[] pastTime = mPastTime; 1426aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1427aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float oldestX = pastX[0]; 1428aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float oldestY = pastY[0]; 1429aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long oldestTime = pastTime[0]; 1430aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float accumX = 0; 1431aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float accumY = 0; 1432aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani int N=0; 1433aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani while (N < NUM_PAST) { 1434aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (pastTime[N] == 0) { 1435aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani break; 1436aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1437aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani N++; 1438aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1439aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1440aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani for (int i=1; i < N; i++) { 1441aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int dur = (int)(pastTime[i] - oldestTime); 1442aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (dur == 0) continue; 1443aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float dist = pastX[i] - oldestX; 1444aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float vel = (dist/dur) * units; // pixels/frame. 1445aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (accumX == 0) accumX = vel; 1446aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani else accumX = (accumX + vel) * .5f; 1447aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1448aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani dist = pastY[i] - oldestY; 1449aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani vel = (dist/dur) * units; // pixels/frame. 1450aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (accumY == 0) accumY = vel; 1451aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani else accumY = (accumY + vel) * .5f; 1452aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1453aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) 1454aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani : Math.min(accumX, maxVelocity); 1455aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) 1456aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani : Math.min(accumY, maxVelocity); 1457aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1458aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1459aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public float getXVelocity() { 1460aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani return mXVelocity; 1461aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1462aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1463aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public float getYVelocity() { 1464aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani return mYVelocity; 1465aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1466aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1468