19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008-2009 Google Inc. 3d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck * 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 7d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck * 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; 260d67c8900276494cd38539bce40342e11ed83508Svetoslav Ganovimport android.graphics.Typeface; 27709349396b0f1e41ccff72f604b516076979745fSvetoslav Ganovimport android.graphics.Paint.Align; 28709349396b0f1e41ccff72f604b516076979745fSvetoslav Ganovimport android.graphics.Region.Op; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.inputmethodservice.Keyboard.Key; 31e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganovimport android.media.AudioManager; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 34b6e0cb97b7d8e4acf345efc8066f1587408b83e0Alan Viveretteimport android.os.UserHandle; 3555f937abe1a4fedb86c2679c66f0b5220ec3780eSvetoslav Ganovimport android.provider.Settings; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 37e403700972f0c3187382c35e9b037b9a4907cf52Amith Yamasaniimport android.util.TypedValue; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.GestureDetector; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 43b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasaniimport android.view.ViewConfiguration; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup.LayoutParams; 45e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 46e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganovimport android.view.accessibility.AccessibilityManager; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.PopupWindow; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 50ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Projectimport com.android.internal.R; 51ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A view that renders a virtual {@link Keyboard}. It handles rendering of keys and 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * detecting key presses and touch movements. 60d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck * 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyBackground 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyPreviewLayout 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyPreviewOffset 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_labelTextSize 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyTextSize 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_keyTextColor 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_verticalCorrection 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#KeyboardView_popupLayout 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class KeyboardView extends View implements View.OnClickListener { 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Listener for virtual keyboard events. 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public interface OnKeyboardActionListener { 76d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user presses a key. This is sent before the {@link #onKey} is called. 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For keys that repeat, this is only called once. 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * key, the value will be zero. 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onPress(int primaryCode); 84d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user releases a key. This is sent after the {@link #onKey} is called. 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For keys that repeat, this is only called once. 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param primaryCode the code of the key that was released 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onRelease(int primaryCode); 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Send a key press to the listener. 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param primaryCode this is the key that was pressed 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param keyCodes the codes for all the possible alternative keys 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with the primary code being the first. If the primary key code is 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a single character such as an alphabet or number or symbol, the alternatives 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will include other characters that may be on the same key or adjacent keys. 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * These codes are useful to correct for accidental presses of a key adjacent to 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the intended key. 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onKey(int primaryCode, int[] keyCodes); 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sends a sequence of characters to the listener. 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param text the sequence of characters to be displayed. 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void onText(CharSequence text); 109d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user quickly moves the finger from right to left. 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void swipeLeft(); 114d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user quickly moves the finger from left to right. 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void swipeRight(); 119d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user quickly moves the finger from up to down. 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void swipeDown(); 124d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the user quickly moves the finger from down to up. 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void swipeUp(); 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean DEBUG = false; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int NOT_A_KEY = -1; 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE }; 134d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck private static final int[] LONG_PRESSABLE_STATE_SET = { R.attr.state_long_pressable }; 135d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Keyboard mKeyboard; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mCurrentKeyIndex = NOT_A_KEY; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLabelTextSize; 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mKeyTextSize; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mKeyTextColor; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mShadowRadius; 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mShadowColor; 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mBackgroundDimAmount; 144d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextView mPreviewText; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PopupWindow mPreviewPopup; 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPreviewTextSizeLarge; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPreviewOffset; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPreviewHeight; 15021334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka // Working variable 15121334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka private final int[] mCoordinates = new int[2]; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PopupWindow mPopupKeyboard; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View mMiniKeyboardContainer; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private KeyboardView mMiniKeyboard; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mMiniKeyboardOnScreen; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View mPopupParent; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMiniKeyboardOffsetX; 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMiniKeyboardOffsetY; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Map<Key,View> mMiniKeyboardCache; 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Key[] mKeys; 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Listener for {@link OnKeyboardActionListener}. */ 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnKeyboardActionListener mKeyboardActionListener; 165d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_SHOW_PREVIEW = 1; 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_REMOVE_PREVIEW = 2; 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_REPEAT = 3; 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_LONGPRESS = 4; 170e403700972f0c3187382c35e9b037b9a4907cf52Amith Yamasani 17129d85df051ca5e888a8f2b42416d09fc931d1a75Amith Yamasani private static final int DELAY_BEFORE_PREVIEW = 0; 17229d85df051ca5e888a8f2b42416d09fc931d1a75Amith Yamasani private static final int DELAY_AFTER_PREVIEW = 70; 1737aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani private static final int DEBOUNCE_TIME = 70; 174d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVerticalCorrection; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mProximityThreshold; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mPreviewCentered = false; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mShowPreview = true; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mShowTouchPoints = true; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupPreviewX; 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupPreviewY; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastX; 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastY; 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mStartX; 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mStartY; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mProximityCorrectOn; 190d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Paint mPaint; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Rect mPadding; 193d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mDownTime; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastMoveTime; 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastKey; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastCodeX; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastCodeY; 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mCurrentKey = NOT_A_KEY; 200aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private int mDownKey = NOT_A_KEY; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastKeyTime; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mCurrentKeyTime; 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mKeyIndices = new int[12]; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private GestureDetector mGestureDetector; 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupX; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupY; 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mRepeatKeyIndex = NOT_A_KEY; 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mPopupLayout; 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mAbortKey; 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Key mInvalidatedKey; 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Rect mClipRegion = new Rect(0, 0, 0, 0); 212aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private boolean mPossiblePoly; 213aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private SwipeTracker mSwipeTracker = new SwipeTracker(); 214aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private int mSwipeThreshold; 215aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private boolean mDisambiguateSwipe; 216e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 217e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Variables for dealing with multiple pointers 218e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani private int mOldPointerCount = 1; 219e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani private float mOldPointerX; 220e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani private float mOldPointerY; 221e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Drawable mKeyBackground; 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int REPEAT_INTERVAL = 50; // ~20 keys per second 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int REPEAT_START_DELAY = 400; 226b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasani private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int MAX_NEARBY_KEYS = 12; 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mDistances = new int[MAX_NEARBY_KEYS]; 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For multi-tap 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLastSentIndex; 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTapCount; 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastTapTime; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mInMultiTap; 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MULTITAP_INTERVAL = 800; // milliseconds 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private StringBuilder mPreviewLabel = new StringBuilder(1); 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 239ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/ 240ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private boolean mDrawPending; 241ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project /** The dirty region in the keyboard bitmap */ 242ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private Rect mDirtyRect = new Rect(); 243ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project /** The keyboard bitmap for faster updates */ 244ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private Bitmap mBuffer; 245e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */ 246e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani private boolean mKeyboardChanged; 247ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project /** The canvas for the above mutable keyboard bitmap */ 248ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private Canvas mCanvas; 249e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov /** The accessibility manager for accessibility support */ 250e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov private AccessibilityManager mAccessibilityManager; 251e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov /** The audio manager for accessibility support */ 252e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov private AudioManager mAudioManager; 253bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov /** Whether the requirement of a headset to hear passwords if accessibility is enabled is announced. */ 254bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov private boolean mHeadsetRequiredToHearPasswordsAnnounced; 255e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov 256d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck Handler mHandler; 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public KeyboardView(Context context, AttributeSet attrs) { 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, attrs, com.android.internal.R.attr.keyboardViewStyle); 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 262617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public KeyboardView(Context context, AttributeSet attrs, int defStyleAttr) { 263617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 264617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 265617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 266617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public KeyboardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 267617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 269617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette TypedArray a = context.obtainStyledAttributes( 270617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette attrs, android.R.styleable.KeyboardView, defStyleAttr, defStyleRes); 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LayoutInflater inflate = 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (LayoutInflater) context 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int previewLayout = 0; 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int keyTextSize = 0; 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int n = a.getIndexCount(); 280d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < n; i++) { 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int attr = a.getIndex(i); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (attr) { 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyBackground: 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyBackground = a.getDrawable(attr); 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_verticalCorrection: 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVerticalCorrection = a.getDimensionPixelOffset(attr, 0); 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyPreviewLayout: 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previewLayout = a.getResourceId(attr, 0); 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyPreviewOffset: 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewOffset = a.getDimensionPixelOffset(attr, 0); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyPreviewHeight: 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewHeight = a.getDimensionPixelSize(attr, 80); 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyTextSize: 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyTextSize = a.getDimensionPixelSize(attr, 18); 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_keyTextColor: 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyTextColor = a.getColor(attr, 0xFF000000); 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_labelTextSize: 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLabelTextSize = a.getDimensionPixelSize(attr, 14); 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_popupLayout: 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupLayout = a.getResourceId(attr, 0); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_shadowColor: 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShadowColor = a.getColor(attr, 0); 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case com.android.internal.R.styleable.KeyboardView_shadowRadius: 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShadowRadius = a.getFloat(attr, 0f); 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 320d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project a = mContext.obtainStyledAttributes( 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.styleable.Theme); 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBackgroundDimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f); 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup = new PopupWindow(context); 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previewLayout != 0) { 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText = (TextView) inflate.inflate(previewLayout, null); 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewTextSizeLarge = (int) mPreviewText.getTextSize(); 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShowPreview = false; 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 334d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.setTouchable(false); 336d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard = new PopupWindow(context); 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.setBackgroundDrawable(null); 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mPopupKeyboard.setClippingEnabled(false); 340d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupParent = this; 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mPredicting = true; 343d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint = new Paint(); 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setAntiAlias(true); 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setTextSize(keyTextSize); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaint.setTextAlign(Align.CENTER); 348e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mPaint.setAlpha(255); 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPadding = new Rect(0, 0, 0, 0); 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardCache = new HashMap<Key,View>(); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyBackground.getPadding(mPadding); 353aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 354aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density); 355aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mDisambiguateSwipe = getResources().getBoolean( 356aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani com.android.internal.R.bool.config_swipeDisambiguation); 357e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov 358e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov mAccessibilityManager = AccessibilityManager.getInstance(context); 359e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 360e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMultiTap(); 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 364d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck @Override 365d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck protected void onAttachedToWindow() { 366d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck super.onAttachedToWindow(); 367d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck initGestureDetector(); 368d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (mHandler == null) { 369d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mHandler = new Handler() { 370d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck @Override 371d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck public void handleMessage(Message msg) { 372d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck switch (msg.what) { 373d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck case MSG_SHOW_PREVIEW: 374d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck showKey(msg.arg1); 375d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck break; 376d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck case MSG_REMOVE_PREVIEW: 377d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mPreviewText.setVisibility(INVISIBLE); 378d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck break; 379d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck case MSG_REPEAT: 380d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (repeatKey()) { 381d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck Message repeat = Message.obtain(this, MSG_REPEAT); 382d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck sendMessageDelayed(repeat, REPEAT_INTERVAL); 383d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 384d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck break; 385d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck case MSG_LONGPRESS: 386d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck openPopupIfRequired((MotionEvent) msg.obj); 387d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck break; 388d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 389d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 390d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck }; 391d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 392d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 393a95e1087b2258b118a7ccb2bedb44da359d3abd0Chet Haase 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void initGestureDetector() { 395d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (mGestureDetector == null) { 396d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { 397d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck @Override 398d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck public boolean onFling(MotionEvent me1, MotionEvent me2, 399d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck float velocityX, float velocityY) { 400d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (mPossiblePoly) return false; 401d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck final float absX = Math.abs(velocityX); 402d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck final float absY = Math.abs(velocityY); 403d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck float deltaX = me2.getX() - me1.getX(); 404d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck float deltaY = me2.getY() - me1.getY(); 405d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck int travelX = getWidth() / 2; // Half the keyboard width 406d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck int travelY = getHeight() / 2; // Half the keyboard height 407d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mSwipeTracker.computeCurrentVelocity(1000); 408d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck final float endingVelocityX = mSwipeTracker.getXVelocity(); 409d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck final float endingVelocityY = mSwipeTracker.getYVelocity(); 410d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck boolean sendDownKey = false; 411d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) { 412d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) { 413d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck sendDownKey = true; 414d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } else { 415d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck swipeRight(); 416d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck return true; 417d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 418d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) { 419d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) { 420d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck sendDownKey = true; 421d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } else { 422d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck swipeLeft(); 423d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck return true; 424d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 425d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) { 426d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) { 427d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck sendDownKey = true; 428d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } else { 429d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck swipeUp(); 430d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck return true; 431d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 432d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) { 433d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) { 434d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck sendDownKey = true; 435d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } else { 436d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck swipeDown(); 437d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck return true; 438d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 439aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 440aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 441d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (sendDownKey) { 442d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime()); 443d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 444d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck return false; 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 446d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck }); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 448d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mGestureDetector.setIsLongpressEnabled(false); 449d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck } 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener = listener; 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the {@link OnKeyboardActionListener} object. 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the listener attached to this keyboard 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected OnKeyboardActionListener getOnKeyboardActionListener() { 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mKeyboardActionListener; 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Attaches a keyboard to this view. The keyboard can be switched at any time and the 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * view will re-layout itself to accommodate the keyboard. 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see Keyboard 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getKeyboard() 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param keyboard the keyboard to display in this view 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setKeyboard(Keyboard keyboard) { 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard != null) { 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(NOT_A_KEY); 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 475ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani // Remove any pending messages 476ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani removeMessages(); 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboard = keyboard; 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<Key> keys = mKeyboard.getKeys(); 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeys = keys.toArray(new Key[keys.size()]); 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 481e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Hint to reallocate the buffer if the size changed 482e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mKeyboardChanged = true; 483f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project computeProximityThreshold(keyboard); 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views 486b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasani // Switching to a different keyboard should abort any pending keys so that the key up 487b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasani // doesn't get delivered to the old or new keyboard 488b974c7a7495849beac1a904fae0839080cd382dcAmith Yamasani mAbortKey = true; // Until the next ACTION_DOWN 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the current keyboard being displayed by this view. 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the currently attached keyboard 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setKeyboard(Keyboard) 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Keyboard getKeyboard() { 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mKeyboard; 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 499d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the state of the shift key of the keyboard, if any. 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param shifted whether or not to enable the state of the shift key 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the shift key state changed, false if there was no change 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see KeyboardView#isShifted() 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean setShifted(boolean shifted) { 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard != null) { 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard.setShifted(shifted)) { 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The whole keyboard probably needs to be redrawn 510f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the state of the shift key of the keyboard, if any. 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the shift is in a pressed state, false otherwise. If there is 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * no shift key on the keyboard or there is no keyboard attached, it returns false. 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see KeyboardView#setShifted(boolean) 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isShifted() { 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard != null) { 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mKeyboard.isShifted(); 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enables or disables the key feedback popup. This is a popup that shows a magnified 532d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck * version of the depressed key. By default the preview is enabled. 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param previewEnabled whether or not to enable the key feedback popup 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #isPreviewEnabled() 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPreviewEnabled(boolean previewEnabled) { 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShowPreview = previewEnabled; 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the enabled state of the key feedback popup. 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return whether or not the key feedback popup is enabled 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setPreviewEnabled(boolean) 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isPreviewEnabled() { 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mShowPreview; 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 548d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVerticalCorrection(int verticalOffset) { 550d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPopupParent(View v) { 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupParent = v; 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 555d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setPopupOffset(int x, int y) { 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardOffsetX = x; 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardOffsetY = y; 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPreviewPopup.isShowing()) { 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.dismiss(); 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 565f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * When enabled, calls to {@link OnKeyboardActionListener#onKey} will include key 566f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * codes for adjacent keys. When disabled, only the primary key code will be 567f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * reported. 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param enabled whether or not the proximity correction is enabled 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setProximityCorrectionEnabled(boolean enabled) { 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProximityCorrectOn = enabled; 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 575f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler * Returns true if proximity correction is enabled. 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isProximityCorrectionEnabled() { 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mProximityCorrectOn; 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 581d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck /** 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Popup keyboard close button clicked. 583d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck * @hide 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onClick(View v) { 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private CharSequence adjustCase(CharSequence label) { 5904df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project if (mKeyboard.isShifted() && label != null && label.length() < 3 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && Character.isLowerCase(label.charAt(0))) { 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project label = label.toString().toUpperCase(); 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return label; 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Round up a little 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard == null) { 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setMeasuredDimension(mPaddingLeft + mPaddingRight, mPaddingTop + mPaddingBottom); 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width = mKeyboard.getMinWidth() + mPaddingLeft + mPaddingRight; 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) { 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project width = MeasureSpec.getSize(widthMeasureSpec); 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setMeasuredDimension(width, mKeyboard.getHeight() + mPaddingTop + mPaddingBottom); 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Compute the average distance between adjacent keys (horizontally and vertically) 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and square it to get the proximity threshold. We use a square here and in computing 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the touch distance from a key's center to avoid taking a square root. 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param keyboard 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void computeProximityThreshold(Keyboard keyboard) { 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyboard == null) return; 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keys == null) return; 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = keys.length; 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dimensionSum = 0; 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < length; i++) { 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key key = keys[i]; 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dimensionSum += Math.min(key.width, key.height) + key.gap; 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dimensionSum < 0 || length == 0) return; 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProximityThreshold = (int) (dimensionSum * 1.4f / length); 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProximityThreshold *= mProximityThreshold; // Square it 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 633ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project public void onSizeChanged(int w, int h, int oldw, int oldh) { 634ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project super.onSizeChanged(w, h, oldw, oldh); 635a95e1087b2258b118a7ccb2bedb44da359d3abd0Chet Haase if (mKeyboard != null) { 636a95e1087b2258b118a7ccb2bedb44da359d3abd0Chet Haase mKeyboard.resize(w, h); 637a95e1087b2258b118a7ccb2bedb44da359d3abd0Chet Haase } 638ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project // Release the buffer, if any and it will be reallocated on the next draw 639ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mBuffer = null; 640ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 641ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 642ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project @Override 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onDraw(Canvas canvas) { 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onDraw(canvas); 645e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (mDrawPending || mBuffer == null || mKeyboardChanged) { 646ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project onBufferDraw(); 647ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 648ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project canvas.drawBitmap(mBuffer, 0, 0, null); 649ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 650e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 651ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project private void onBufferDraw() { 652e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (mBuffer == null || mKeyboardChanged) { 653e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (mBuffer == null || mKeyboardChanged && 654e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) { 65546a61bb730e1f144511be49722af573aba73edbaRomain Guy // Make sure our bitmap is at least 1x1 65646a61bb730e1f144511be49722af573aba73edbaRomain Guy final int width = Math.max(1, getWidth()); 65746a61bb730e1f144511be49722af573aba73edbaRomain Guy final int height = Math.max(1, getHeight()); 65846a61bb730e1f144511be49722af573aba73edbaRomain Guy mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 659e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mCanvas = new Canvas(mBuffer); 660e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 661f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 662e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mKeyboardChanged = false; 663ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 664ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project final Canvas canvas = mCanvas; 665ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project canvas.clipRect(mDirtyRect, Op.REPLACE); 666d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKeyboard == null) return; 668d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Paint paint = mPaint; 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Drawable keyBackground = mKeyBackground; 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Rect clipRegion = mClipRegion; 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Rect padding = mPadding; 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int kbdPaddingLeft = mPaddingLeft; 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int kbdPaddingTop = mPaddingTop; 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key invalidKey = mInvalidatedKey; 677ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor(mKeyTextColor); 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean drawSingleKey = false; 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (invalidKey != null && canvas.getClipBounds(clipRegion)) { 681ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project // Is clipRegion completely contained within the invalidated key? 682ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left && 683ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top && 684ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right && 685ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) { 686ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project drawSingleKey = true; 687ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 689ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int keyCount = keys.length; 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < keyCount; i++) { 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key key = keys[i]; 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (drawSingleKey && invalidKey != key) { 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] drawableState = key.getCurrentDrawableState(); 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyBackground.setState(drawableState); 698e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Switch the character to uppercase if shift is pressed 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String label = key.label == null? null : adjustCase(key.label).toString(); 701d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Rect bounds = keyBackground.getBounds(); 703d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (key.width != bounds.right || 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.height != bounds.bottom) { 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyBackground.setBounds(0, 0, key.width, key.height); 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop); 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyBackground.draw(canvas); 709d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (label != null) { 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For characters, use large font. For labels like "Done", use small font. 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (label.length() > 1 && key.codes.length < 2) { 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setTextSize(mLabelTextSize); 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setTypeface(Typeface.DEFAULT_BOLD); 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setTextSize(mKeyTextSize); 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setTypeface(Typeface.DEFAULT); 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Draw a drop shadow for the text 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor); 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Draw the text 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawText(label, 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (key.width - padding.left - padding.right) / 2 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + padding.left, 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (key.height - padding.top - padding.bottom) / 2 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (paint.getTextSize() - paint.descent()) / 2 + padding.top, 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint); 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Turn off drop shadow 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setShadowLayer(0, 0, 0, 0); 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (key.icon != null) { 731d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck final int drawableX = (key.width - padding.left - padding.right 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project - key.icon.getIntrinsicWidth()) / 2 + padding.left; 733d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck final int drawableY = (key.height - padding.top - padding.bottom 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project - key.icon.getIntrinsicHeight()) / 2 + padding.top; 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(drawableX, drawableY); 736d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck key.icon.setBounds(0, 0, 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight()); 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.icon.draw(canvas); 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(-drawableX, -drawableY); 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop); 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInvalidatedKey = null; 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Overlay a dark rectangle to dim the keyboard 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMiniKeyboardOnScreen) { 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawRect(0, 0, getWidth(), getHeight(), paint); 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DEBUG && mShowTouchPoints) { 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setAlpha(128); 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor(0xFFFF0000); 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawCircle(mStartX, mStartY, 3, paint); 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawLine(mStartX, mStartY, mLastX, mLastY, paint); 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor(0xFF0000FF); 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawCircle(mLastX, mLastY, 3, paint); 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.setColor(0xFF00FF00); 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint); 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 760d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 761ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDrawPending = false; 762ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDirtyRect.setEmpty(); 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getKeyIndices(int x, int y, int[] allKeys) { 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int primaryIndex = NOT_A_KEY; 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int closestKey = NOT_A_KEY; 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int closestKeyDist = mProximityThreshold + 1; 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project java.util.Arrays.fill(mDistances, Integer.MAX_VALUE); 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int keyCount = nearestKeyIndices.length; 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < keyCount; i++) { 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key key = keys[nearestKeyIndices[i]]; 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int dist = 0; 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean isInside = key.isInside(x,y); 777ec5df83c5b44ad2f2b28a1a4420c4c4056dd6103Amith Yamasani if (isInside) { 778ec5df83c5b44ad2f2b28a1a4420c4c4056dd6103Amith Yamasani primaryIndex = nearestKeyIndices[i]; 779ec5df83c5b44ad2f2b28a1a4420c4c4056dd6103Amith Yamasani } 780ec5df83c5b44ad2f2b28a1a4420c4c4056dd6103Amith Yamasani 781d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck if (((mProximityCorrectOn 782d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold) 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || isInside) 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && key.codes[0] > 32) { 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Find insertion point 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int nCodes = key.codes.length; 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dist < closestKeyDist) { 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closestKeyDist = dist; 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closestKey = nearestKeyIndices[i]; 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 791d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (allKeys == null) continue; 793d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mDistances.length; j++) { 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDistances[j] > dist) { 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make space for nCodes codes 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(mDistances, j, mDistances, j + nCodes, 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDistances.length - j - nCodes); 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(allKeys, j, allKeys, j + nCodes, 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project allKeys.length - j - nCodes); 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int c = 0; c < nCodes; c++) { 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project allKeys[j + c] = key.codes[c]; 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDistances[j + c] = dist; 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (primaryIndex == NOT_A_KEY) { 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project primaryIndex = closestKey; 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return primaryIndex; 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 816aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private void detectAndSendKey(int index, int x, int y, long eventTime) { 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (index != NOT_A_KEY && index < mKeys.length) { 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key key = mKeys[index]; 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.text != null) { 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onText(key.text); 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onRelease(NOT_A_KEY); 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int code = key.codes[0]; 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //TextEntryState.keyPressedAt(key, x, y); 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] codes = new int[MAX_NEARBY_KEYS]; 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Arrays.fill(codes, NOT_A_KEY); 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getKeyIndices(x, y, codes); 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Multi-tap 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInMultiTap) { 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mTapCount != -1) { 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE); 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTapCount = 0; 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project code = key.codes[mTapCount]; 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onKey(code, codes); 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onRelease(code); 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastSentIndex = index; 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastTapTime = eventTime; 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handle multi-tap keys by producing the key label for the current multi-tap state. 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private CharSequence getPreviewText(Key key) { 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mInMultiTap) { 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Multi-tap 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewLabel.setLength(0); 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]); 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return adjustCase(mPreviewLabel); 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return adjustCase(key.label); 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 858d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void showPreview(int keyIndex) { 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldKeyIndex = mCurrentKeyIndex; 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final PopupWindow previewPopup = mPreviewPopup; 862d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyIndex = keyIndex; 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Release the old key and press the new key 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldKeyIndex != mCurrentKeyIndex) { 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) { 868e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov Key oldKey = keys[oldKeyIndex]; 869e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov oldKey.onReleased(mCurrentKeyIndex == NOT_A_KEY); 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidateKey(oldKeyIndex); 871b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov final int keyCode = oldKey.codes[0]; 872bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT, 873b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov keyCode); 874b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov // TODO: We need to implement AccessibilityNodeProvider for this view. 875b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov sendAccessibilityEventForUnicodeCharacter( 876b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, keyCode); 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) { 879e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov Key newKey = keys[mCurrentKeyIndex]; 880e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov newKey.onPressed(); 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidateKey(mCurrentKeyIndex); 882b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov final int keyCode = newKey.codes[0]; 883bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, 884b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov keyCode); 885b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov // TODO: We need to implement AccessibilityNodeProvider for this view. 886b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov sendAccessibilityEventForUnicodeCharacter( 887b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, keyCode); 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If key changed and preview is on ... 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldKeyIndex != mCurrentKeyIndex && mShowPreview) { 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeMessages(MSG_SHOW_PREVIEW); 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previewPopup.isShowing()) { 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex == NOT_A_KEY) { 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed(mHandler 896d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck .obtainMessage(MSG_REMOVE_PREVIEW), 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DELAY_AFTER_PREVIEW); 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex != NOT_A_KEY) { 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Show right away, if it's already visible and finger is moving around 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showKey(keyIndex); 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed( 906d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0), 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DELAY_BEFORE_PREVIEW); 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 912d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void showKey(final int keyIndex) { 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final PopupWindow previewPopup = mPreviewPopup; 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key[] keys = mKeys; 916ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani if (keyIndex < 0 || keyIndex >= mKeys.length) return; 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key key = keys[keyIndex]; 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.icon != null) { 919d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mPreviewText.setCompoundDrawables(null, null, null, 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.iconPreview != null ? key.iconPreview : key.icon); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setText(null); 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setCompoundDrawables(null, null, null, null); 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setText(getPreviewText(key)); 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.label.length() > 1 && key.codes.length < 2) { 926e403700972f0c3187382c35e9b037b9a4907cf52Amith Yamasani mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize); 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 929e403700972f0c3187382c35e9b037b9a4907cf52Amith Yamasani mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge); 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setTypeface(Typeface.DEFAULT); 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 933d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 935d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int popupHeight = mPreviewHeight; 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LayoutParams lp = mPreviewText.getLayoutParams(); 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lp != null) { 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lp.width = popupWidth; 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lp.height = popupHeight; 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mPreviewCentered) { 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft; 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupPreviewY = key.y - popupHeight + mPreviewOffset; 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Fix this if centering is brought back 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2; 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupPreviewY = - mPreviewText.getMeasuredHeight(); 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeMessages(MSG_REMOVE_PREVIEW); 95221334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka getLocationInWindow(mCoordinates); 95321334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka mCoordinates[0] += mMiniKeyboardOffsetX; // Offset may be zero 95421334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka mCoordinates[1] += mMiniKeyboardOffsetY; // Offset may be zero 95521334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set the preview background state 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.getBackground().setState( 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); 95921334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka mPopupPreviewX += mCoordinates[0]; 96021334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka mPopupPreviewY += mCoordinates[1]; 96142973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani 96242973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani // If the popup cannot be shown above the key, put it on the side 96321334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka getLocationOnScreen(mCoordinates); 96421334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka if (mPopupPreviewY + mCoordinates[1] < 0) { 96542973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani // If the key you're pressing is on the left side of the keyboard, show the popup on 96642973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani // the right, offset by enough to see at least one key to the left/right. 96742973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani if (key.x + key.width <= getWidth() / 2) { 96842973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewX += (int) (key.width * 2.5); 96942973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani } else { 97042973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewX -= (int) (key.width * 2.5); 97142973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani } 97242973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewY += popupHeight; 97342973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani } 97442973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (previewPopup.isShowing()) { 97642973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani previewPopup.update(mPopupPreviewX, mPopupPreviewY, 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project popupWidth, popupHeight); 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previewPopup.setWidth(popupWidth); 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previewPopup.setHeight(popupHeight); 981d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, 98242973a4a03ac6ebea94b4d4db1b319c7d45f720dAmith Yamasani mPopupPreviewX, mPopupPreviewY); 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewText.setVisibility(VISIBLE); 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 987bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov private void sendAccessibilityEventForUnicodeCharacter(int eventType, int code) { 988e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov if (mAccessibilityManager.isEnabled()) { 989e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 990e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov onInitializeAccessibilityEvent(event); 991bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov String text = null; 99255f937abe1a4fedb86c2679c66f0b5220ec3780eSvetoslav Ganov // This is very efficient since the properties are cached. 993b6e0cb97b7d8e4acf345efc8066f1587408b83e0Alan Viverette final boolean speakPassword = Settings.Secure.getIntForUser( 994b6e0cb97b7d8e4acf345efc8066f1587408b83e0Alan Viverette mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0, 9959752428dc1829450e90417ca3e46d077e915ae90Alan Viverette UserHandle.USER_CURRENT_OR_SELF) != 0; 99655f937abe1a4fedb86c2679c66f0b5220ec3780eSvetoslav Ganov // Add text only if password announcement is enabled or if headset is 99755f937abe1a4fedb86c2679c66f0b5220ec3780eSvetoslav Ganov // used to avoid leaking passwords. 99855f937abe1a4fedb86c2679c66f0b5220ec3780eSvetoslav Ganov if (speakPassword || mAudioManager.isBluetoothA2dpOn() 99955f937abe1a4fedb86c2679c66f0b5220ec3780eSvetoslav Ganov || mAudioManager.isWiredHeadsetOn()) { 1000e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov switch (code) { 1001e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov case Keyboard.KEYCODE_ALT: 1002e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov text = mContext.getString(R.string.keyboardview_keycode_alt); 1003e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov break; 1004e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov case Keyboard.KEYCODE_CANCEL: 1005e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov text = mContext.getString(R.string.keyboardview_keycode_cancel); 1006e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov break; 1007e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov case Keyboard.KEYCODE_DELETE: 1008e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov text = mContext.getString(R.string.keyboardview_keycode_delete); 1009e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov break; 1010e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov case Keyboard.KEYCODE_DONE: 1011e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov text = mContext.getString(R.string.keyboardview_keycode_done); 1012e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov break; 1013e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov case Keyboard.KEYCODE_MODE_CHANGE: 1014e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov text = mContext.getString(R.string.keyboardview_keycode_mode_change); 1015e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov break; 1016e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov case Keyboard.KEYCODE_SHIFT: 1017e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov text = mContext.getString(R.string.keyboardview_keycode_shift); 1018e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov break; 1019e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov case '\n': 1020e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov text = mContext.getString(R.string.keyboardview_keycode_enter); 1021e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov break; 1022e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov default: 1023e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov text = String.valueOf((char) code); 1024e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov } 1025bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov } else if (!mHeadsetRequiredToHearPasswordsAnnounced) { 1026bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov // We want the waring for required head set to be send with both the 1027bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov // hover enter and hover exit event, so set the flag after the exit. 1028bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov if (eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { 1029bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov mHeadsetRequiredToHearPasswordsAnnounced = true; 1030bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov } 1031bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov text = mContext.getString(R.string.keyboard_headset_required_to_hear_password); 1032e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov } else { 1033bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov text = mContext.getString(R.string.keyboard_password_character_no_headset); 1034e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov } 1035bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov event.getText().add(text); 1036e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov mAccessibilityManager.sendAccessibilityEvent(event); 1037e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov } 1038e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov } 1039e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov 1040f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani /** 1041f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient 1042d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck * because the keyboard renders the keys to an off-screen buffer and an invalidate() only 1043f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * draws the cached buffer. 1044f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * @see #invalidateKey(int) 1045f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani */ 1046f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani public void invalidateAllKeys() { 1047ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDirtyRect.union(0, 0, getWidth(), getHeight()); 1048ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mDrawPending = true; 1049ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidate(); 1050ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project } 1051f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani 1052f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani /** 1053f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * Invalidates a key so that it will be redrawn on the next repaint. Use this method if only 1054f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * one key is changing it's content. Any changes that affect the position or size of the key 1055f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * may not be honored. 1056f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * @param keyIndex the index of the key in the attached {@link Keyboard}. 1057f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani * @see #invalidateAllKeys 1058f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani */ 1059f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani public void invalidateKey(int keyIndex) { 1060f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani if (mKeys == null) return; 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex < 0 || keyIndex >= mKeys.length) { 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Key key = mKeys[keyIndex]; 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInvalidatedKey = key; 1066d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mDirtyRect.union(key.x + mPaddingLeft, key.y + mPaddingTop, 1067ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop); 1068ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project onBufferDraw(); 1069d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck invalidate(key.x + mPaddingLeft, key.y + mPaddingTop, 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop); 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean openPopupIfRequired(MotionEvent me) { 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check if we have a popup layout specified first. 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPopupLayout == 0) { 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKey < 0 || mCurrentKey >= mKeys.length) { 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1082d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck Key popupKey = mKeys[mCurrentKey]; 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean result = onLongPress(popupKey); 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result) { 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAbortKey = true; 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(NOT_A_KEY); 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when a key is long pressed. By default this will open any popup keyboard associated 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with this key through the attributes popupLayout and popupCharacters. 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param popupKey the key that was long pressed 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the long press is handled, false otherwise. Subclasses should call the 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * method on the base class if the subclass doesn't wish to handle the call. 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected boolean onLongPress(Key popupKey) { 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int popupKeyboardId = popupKey.popupResId; 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (popupKeyboardId != 0) { 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey); 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMiniKeyboardContainer == null) { 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Context.LAYOUT_INFLATER_SERVICE); 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null); 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById( 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.id.keyboardView); 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View closeButton = mMiniKeyboardContainer.findViewById( 111088fb1069bf254dc68c83546496592a9b5e739a07Dianne Hackborn com.android.internal.R.id.closeButton); 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (closeButton != null) closeButton.setOnClickListener(this); 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onKey(int primaryCode, int[] keyCodes) { 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onKey(primaryCode, keyCodes); 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1117d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onText(CharSequence text) { 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onText(text); 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1122d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void swipeLeft() { } 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void swipeRight() { } 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void swipeUp() { } 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void swipeDown() { } 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onPress(int primaryCode) { 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onPress(primaryCode); 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onRelease(int primaryCode) { 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.onRelease(primaryCode); 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mInputView.setSuggest(mSuggest); 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Keyboard keyboard; 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (popupKey.popupCharacters != null) { 1137d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck keyboard = new Keyboard(getContext(), popupKeyboardId, 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight()); 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keyboard = new Keyboard(getContext(), popupKeyboardId); 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setKeyboard(keyboard); 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setPopupParent(this); 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardContainer.measure( 1145d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), 11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); 1147d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer); 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById( 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project com.android.internal.R.id.keyboardView); 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 115321334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka getLocationInWindow(mCoordinates); 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupX = popupKey.x + mPaddingLeft; 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupY = popupKey.y + mPaddingTop; 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth(); 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight(); 115821334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mCoordinates[0]; 115921334fdbbe9f2e6890fb9877b9ef3d441f3eb6fbTadashi G. Takaoka final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mCoordinates[1]; 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y); 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboard.setShifted(isShifted()); 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.setContentView(mMiniKeyboardContainer); 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth()); 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight()); 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y); 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardOnScreen = true; 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me)); 1168f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1173e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 1174e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov @Override 1175bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov public boolean onHoverEvent(MotionEvent event) { 1176bd39ca701492cb4dccfbe70c7bb76219979326a4Svetoslav Ganov if (mAccessibilityManager.isTouchExplorationEnabled() && event.getPointerCount() == 1) { 1177e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov final int action = event.getAction(); 1178e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov switch (action) { 1179b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov case MotionEvent.ACTION_HOVER_ENTER: { 1180b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov event.setAction(MotionEvent.ACTION_DOWN); 1181b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov } break; 1182b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov case MotionEvent.ACTION_HOVER_MOVE: { 1183b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov event.setAction(MotionEvent.ACTION_MOVE); 1184b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov } break; 1185b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov case MotionEvent.ACTION_HOVER_EXIT: { 1186b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov event.setAction(MotionEvent.ACTION_UP); 1187b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov } break; 1188e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov } 1189b6a0b09bf570679587f1875ef336dfe676ea8ebeSvetoslav Ganov return onTouchEvent(event); 1190e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov } 119167578618fb7ac1bf353d7caaadf9a49c09be5d07Svetoslav Ganov return true; 1192e8b8e1aed046711b41804de1670e58c7a8a9d6adSvetoslav Ganov } 1193aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 119567578618fb7ac1bf353d7caaadf9a49c09be5d07Svetoslav Ganov public boolean onTouchEvent(MotionEvent me) { 1196d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck // Convert multi-pointer up/down events to single up/down events to 1197e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // deal with the typical multi-pointer behavior of two-thumb typing 1198aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int pointerCount = me.getPointerCount(); 1199aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int action = me.getAction(); 1200e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani boolean result = false; 1201aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long now = me.getEventTime(); 1202aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1203e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (pointerCount != mOldPointerCount) { 1204e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (pointerCount == 1) { 1205e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Send a down event for the latest pointer 1206e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 1207e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani me.getX(), me.getY(), me.getMetaState()); 1208aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani result = onModifiedTouchEvent(down, false); 1209e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani down.recycle(); 12108b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani // If it's an up action, then deliver the up as well. 1211aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (action == MotionEvent.ACTION_UP) { 1212aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani result = onModifiedTouchEvent(me, true); 12138b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani } 1214e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } else { 1215e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Send an up event for the last pointer 1216e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 1217e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mOldPointerX, mOldPointerY, me.getMetaState()); 1218aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani result = onModifiedTouchEvent(up, true); 1219e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani up.recycle(); 1220e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 1221e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } else { 1222e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani if (pointerCount == 1) { 1223aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani result = onModifiedTouchEvent(me, false); 1224e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mOldPointerX = me.getX(); 1225e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mOldPointerY = me.getY(); 1226e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } else { 1227e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani // Don't do anything when 2 pointers are down and moving. 1228e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani result = true; 1229e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 1230e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 1231e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani mOldPointerCount = pointerCount; 1232aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1233e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani return result; 1234e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani } 1235e877ec632c3338234eb89c89c3dd8a68267b8633Amith Yamasani 1236aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private boolean onModifiedTouchEvent(MotionEvent me, boolean possiblePoly) { 1237678cdbe55e0de71436f8aad5f139eafc2ab6f937Amith Yamasani int touchX = (int) me.getX() - mPaddingLeft; 12380972d071cd1b5eba60a6c20551f4500b638a1bf1Tadashi G. Takaoka int touchY = (int) me.getY() - mPaddingTop; 12390972d071cd1b5eba60a6c20551f4500b638a1bf1Tadashi G. Takaoka if (touchY >= -mVerticalCorrection) 12400972d071cd1b5eba60a6c20551f4500b638a1bf1Tadashi G. Takaoka touchY += mVerticalCorrection; 1241aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int action = me.getAction(); 1242aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long eventTime = me.getEventTime(); 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int keyIndex = getKeyIndices(touchX, touchY, null); 1244aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mPossiblePoly = possiblePoly; 1245aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1246aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani // Track the last few movements to look for spurious swipes. 1247aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (action == MotionEvent.ACTION_DOWN) mSwipeTracker.clear(); 1248aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mSwipeTracker.addMovement(me); 1249aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 12504d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani // Ignore all motion events until a DOWN. 12517aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani if (mAbortKey 12527aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) { 12534d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani return true; 12544d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani } 12554d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mGestureDetector.onTouchEvent(me)) { 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(NOT_A_KEY); 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeMessages(MSG_REPEAT); 12598b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani mHandler.removeMessages(MSG_LONGPRESS); 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1262d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Needs to be called after the gesture detector gets a turn, as it may have 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // displayed the mini keyboard 12650743a389e8fd1e696c2c02e22689b2d6f12dc48bAmith Yamasani if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) { 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (action) { 12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_DOWN: 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAbortKey = false; 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStartX = touchX; 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStartY = touchY; 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastCodeX = touchX; 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastCodeY = touchY; 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKeyTime = 0; 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime = 0; 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKey = NOT_A_KEY; 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = keyIndex; 1280aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mDownKey = keyIndex; 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDownTime = me.getEventTime(); 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastMoveTime = mDownTime; 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkMultiTap(eventTime, keyIndex); 1284d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ? 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeys[keyIndex].codes[0] : 0); 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) { 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRepeatKeyIndex = mCurrentKey; 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message msg = mHandler.obtainMessage(MSG_REPEAT); 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY); 12904d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani repeatKey(); 12914d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani // Delivering the key could have caused an abort 12924d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani if (mAbortKey) { 12934d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani mRepeatKeyIndex = NOT_A_KEY; 12944d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani break; 12954d2c27b145969f4467cf70037eecf730572dcf5dAmith Yamasani } 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKey != NOT_A_KEY) { 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me); 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT); 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(keyIndex); 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_MOVE: 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean continueLongPress = false; 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex != NOT_A_KEY) { 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCurrentKey == NOT_A_KEY) { 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = keyIndex; 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime = eventTime - mDownTime; 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex == mCurrentKey) { 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime += eventTime - mLastMoveTime; 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continueLongPress = true; 13148b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani } else if (mRepeatKeyIndex == NOT_A_KEY) { 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMultiTap(); 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKey = mCurrentKey; 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastCodeX = mLastX; 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastCodeY = mLastY; 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKeyTime = 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime + eventTime - mLastMoveTime; 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = keyIndex; 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime = 0; 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!continueLongPress) { 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Cancel old longpress 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.removeMessages(MSG_LONGPRESS); 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Start new longpress if key has changed 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex != NOT_A_KEY) { 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me); 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT); 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13358b37eb0c2a94d32c012a2709ddb0effc985b1d65Amith Yamasani showPreview(mCurrentKey); 13367aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani mLastMoveTime = eventTime; 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MotionEvent.ACTION_UP: 1340ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani removeMessages(); 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex == mCurrentKey) { 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime += eventTime - mLastMoveTime; 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMultiTap(); 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKey = mCurrentKey; 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime; 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = keyIndex; 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKeyTime = 0; 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13507aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani if (mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < DEBOUNCE_TIME 13517aa936e8368268c3cca7c3fd23fde7fd02318c58Amith Yamasani && mLastKey != NOT_A_KEY) { 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentKey = mLastKey; 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project touchX = mLastCodeX; 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project touchY = mLastCodeY; 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showPreview(NOT_A_KEY); 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Arrays.fill(mKeyIndices, NOT_A_KEY); 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If we're not on a repeating key (which sends on a DOWN event) 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) { 1360aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani detectAndSendKey(mCurrentKey, touchX, touchY, eventTime); 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1362ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project invalidateKey(keyIndex); 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRepeatKeyIndex = NOT_A_KEY; 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1365aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani case MotionEvent.ACTION_CANCEL: 1366aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani removeMessages(); 13670743a389e8fd1e696c2c02e22689b2d6f12dc48bAmith Yamasani dismissPopupKeyboard(); 1368aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mAbortKey = true; 1369aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani showPreview(NOT_A_KEY); 1370aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani invalidateKey(mCurrentKey); 1371aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani break; 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastX = touchX; 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastY = touchY; 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean repeatKey() { 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key key = mKeys[mRepeatKeyIndex]; 1380aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime); 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1383d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void swipeRight() { 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.swipeRight(); 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1387d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void swipeLeft() { 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.swipeLeft(); 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void swipeUp() { 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.swipeUp(); 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void swipeDown() { 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKeyboardActionListener.swipeDown(); 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void closing() { 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPreviewPopup.isShowing()) { 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewPopup.dismiss(); 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1404ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani removeMessages(); 1405d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 1407ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mBuffer = null; 1408ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project mCanvas = null; 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardCache.clear(); 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1411ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani 1412ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani private void removeMessages() { 14135ba31aa77d4319c3a473d626c5bd48be5c3a0dd2Clara Bayarri if (mHandler != null) { 14145ba31aa77d4319c3a473d626c5bd48be5c3a0dd2Clara Bayarri mHandler.removeMessages(MSG_REPEAT); 14155ba31aa77d4319c3a473d626c5bd48be5c3a0dd2Clara Bayarri mHandler.removeMessages(MSG_LONGPRESS); 14165ba31aa77d4319c3a473d626c5bd48be5c3a0dd2Clara Bayarri mHandler.removeMessages(MSG_SHOW_PREVIEW); 14175ba31aa77d4319c3a473d626c5bd48be5c3a0dd2Clara Bayarri } 1418ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani } 1419ebe3d518ffaeb14f3f2e0e74cdbc15fd2ddf4453Amith Yamasani 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onDetachedFromWindow() { 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onDetachedFromWindow(); 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project closing(); 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void dismissPopupKeyboard() { 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPopupKeyboard.isShowing()) { 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPopupKeyboard.dismiss(); 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMiniKeyboardOnScreen = false; 1430f04da95400e409dbb4ba33653f075bc76e091ef1Amith Yamasani invalidateAllKeys(); 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1433ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean handleBack() { 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPopupKeyboard.isShowing()) { 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissPopupKeyboard(); 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void resetMultiTap() { 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastSentIndex = NOT_A_KEY; 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTapCount = 0; 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastTapTime = -1; 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInMultiTap = false; 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1448d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void checkMultiTap(long eventTime, int keyIndex) { 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyIndex == NOT_A_KEY) return; 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Key key = mKeys[keyIndex]; 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (key.codes.length > 1) { 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInMultiTap = true; 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (eventTime < mLastTapTime + MULTITAP_INTERVAL 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && keyIndex == mLastSentIndex) { 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTapCount = (mTapCount + 1) % key.codes.length; 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTapCount = -1; 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) { 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMultiTap(); 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1467aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1468aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private static class SwipeTracker { 1469aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1470aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani static final int NUM_PAST = 4; 1471aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani static final int LONGEST_PAST_TIME = 200; 1472aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1473aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float mPastX[] = new float[NUM_PAST]; 1474aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float mPastY[] = new float[NUM_PAST]; 1475aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long mPastTime[] = new long[NUM_PAST]; 1476aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1477aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float mYVelocity; 1478aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float mXVelocity; 1479aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1480aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public void clear() { 1481aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mPastTime[0] = 0; 1482aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1483aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1484aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public void addMovement(MotionEvent ev) { 1485aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani long time = ev.getEventTime(); 1486aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int N = ev.getHistorySize(); 1487aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani for (int i=0; i<N; i++) { 1488aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i), 1489aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani ev.getHistoricalEventTime(i)); 1490aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1491aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani addPoint(ev.getX(), ev.getY(), time); 1492aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1493aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1494aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani private void addPoint(float x, float y, long time) { 1495aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani int drop = -1; 1496aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani int i; 1497aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long[] pastTime = mPastTime; 1498aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani for (i=0; i<NUM_PAST; i++) { 1499aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (pastTime[i] == 0) { 1500aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani break; 1501aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } else if (pastTime[i] < time-LONGEST_PAST_TIME) { 1502aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani drop = i; 1503aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1504aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1505aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (i == NUM_PAST && drop < 0) { 1506aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani drop = 0; 1507aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1508aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (drop == i) drop--; 1509aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float[] pastX = mPastX; 1510aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float[] pastY = mPastY; 1511aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (drop >= 0) { 1512aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int start = drop+1; 1513aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int count = NUM_PAST-drop-1; 1514aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani System.arraycopy(pastX, start, pastX, 0, count); 1515aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani System.arraycopy(pastY, start, pastY, 0, count); 1516aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani System.arraycopy(pastTime, start, pastTime, 0, count); 1517aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani i -= (drop+1); 1518aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1519aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani pastX[i] = x; 1520aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani pastY[i] = y; 1521aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani pastTime[i] = time; 1522aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani i++; 1523aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (i < NUM_PAST) { 1524aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani pastTime[i] = 0; 1525aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1526aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1527aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1528aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public void computeCurrentVelocity(int units) { 1529aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani computeCurrentVelocity(units, Float.MAX_VALUE); 1530aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1531aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1532aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public void computeCurrentVelocity(int units, float maxVelocity) { 1533aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float[] pastX = mPastX; 1534aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float[] pastY = mPastY; 1535aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long[] pastTime = mPastTime; 1536aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1537aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float oldestX = pastX[0]; 1538aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final float oldestY = pastY[0]; 1539aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final long oldestTime = pastTime[0]; 1540aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float accumX = 0; 1541aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float accumY = 0; 1542aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani int N=0; 1543aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani while (N < NUM_PAST) { 1544aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (pastTime[N] == 0) { 1545aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani break; 1546aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1547aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani N++; 1548aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1549aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1550aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani for (int i=1; i < N; i++) { 1551aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani final int dur = (int)(pastTime[i] - oldestTime); 1552aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (dur == 0) continue; 1553aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float dist = pastX[i] - oldestX; 1554aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani float vel = (dist/dur) * units; // pixels/frame. 1555aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (accumX == 0) accumX = vel; 1556aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani else accumX = (accumX + vel) * .5f; 1557aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1558aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani dist = pastY[i] - oldestY; 1559aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani vel = (dist/dur) * units; // pixels/frame. 1560aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani if (accumY == 0) accumY = vel; 1561aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani else accumY = (accumY + vel) * .5f; 1562aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1563aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) 1564aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani : Math.min(accumX, maxVelocity); 1565aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) 1566aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani : Math.min(accumY, maxVelocity); 1567aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1568aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1569aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public float getXVelocity() { 1570aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani return mXVelocity; 1571aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1572aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani 1573aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani public float getYVelocity() { 1574aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani return mYVelocity; 1575aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 1576aea1b3b24ee895c24ed25c5706bc2f390b41689dAmith Yamasani } 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1578