159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma/* 259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Copyright (C) 2008-2012 OMRON SOFTWARE Co., Ltd. 359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Licensed under the Apache License, Version 2.0 (the "License"); 559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * you may not use this file except in compliance with the License. 659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * You may obtain a copy of the License at 759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * http://www.apache.org/licenses/LICENSE-2.0 959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 1059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Unless required by applicable law or agreed to in writing, software 1159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * distributed under the License is distributed on an "AS IS" BASIS, 1259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * See the License for the specific language governing permissions and 1459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * limitations under the License. 1559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 1659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma/* This file is porting from Android framework. 1759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * frameworks/base/core/java/android/inputmethodservice/KeyboardView.java 1859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * 1959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma *package android.inputmethodservice; 2059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 2159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 2259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmapackage jp.co.omronsoft.openwnn; 2359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 2459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.content.Context; 2559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.content.res.TypedArray; 2659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.Bitmap; 2759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.Canvas; 2859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.Paint; 2959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.PorterDuff; 3059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.Rect; 3159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.Typeface; 3259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.Paint.Align; 3359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.Region.Op; 3459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.graphics.drawable.Drawable; 3559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.os.Handler; 3659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.os.Message; 3759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.util.AttributeSet; 3859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.util.TypedValue; 3959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.view.GestureDetector; 4059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.view.Gravity; 4159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.view.LayoutInflater; 4259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.view.MotionEvent; 4359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.view.View; 4459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.view.ViewConfiguration; 4559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.view.ViewGroup.LayoutParams; 4659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.widget.PopupWindow; 4759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport android.widget.TextView; 4859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 4959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport jp.co.omronsoft.openwnn.Keyboard; 5059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport jp.co.omronsoft.openwnn.Keyboard.Key; 5159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 5259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport java.util.Arrays; 5359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport java.util.HashMap; 5459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport java.util.List; 5559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmaimport java.util.Map; 5659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 5759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma/** 5859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * A view that renders a virtual {@link Keyboard}. It handles rendering of keys and 5959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * detecting key presses and touch movements. 6059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 6159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monmapublic class KeyboardView extends View implements View.OnClickListener { 6259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 6359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 6459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Listener for virtual keyboard events. 6559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 6659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public interface OnKeyboardActionListener { 6759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 6859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 6959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Called when the user presses a key. This is sent before the {@link #onKey} is called. 7059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * For keys that repeat, this is only called once. 7159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid 7259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * key, the value will be zero. 7359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 7459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma void onPress(int primaryCode); 7559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 7659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 7759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Called when the user releases a key. This is sent after the {@link #onKey} is called. 7859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * For keys that repeat, this is only called once. 7959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param primaryCode the code of the key that was released 8059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 8159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma void onRelease(int primaryCode); 8259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 8359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 8459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Send a key press to the listener. 8559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param primaryCode this is the key that was pressed 8659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param keyCodes the codes for all the possible alternative keys 8759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * with the primary code being the first. If the primary key code is 8859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * a single character such as an alphabet or number or symbol, the alternatives 8959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * will include other characters that may be on the same key or adjacent keys. 9059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * These codes are useful to correct for accidental presses of a key adjacent to 9159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * the intended key. 9259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 9359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma void onKey(int primaryCode, int[] keyCodes); 9459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 9559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 9659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Sends a sequence of characters to the listener. 9759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param text the sequence of characters to be displayed. 9859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 9959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma void onText(CharSequence text); 10059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 10159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 10259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Called when the user quickly moves the finger from right to left. 10359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 10459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma void swipeLeft(); 10559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 10659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 10759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Called when the user quickly moves the finger from left to right. 10859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 10959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma void swipeRight(); 11059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 11159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 11259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Called when the user quickly moves the finger from up to down. 11359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 11459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma void swipeDown(); 11559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 11659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 11759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Called when the user quickly moves the finger from down to up. 11859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 11959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma void swipeUp(); 12059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 12159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 12259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Called when the user long presses a key. 12359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param popupKey the key that was long pressed 12459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return true if the long press is handled, false otherwise. 12559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 12659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean onLongPress(Keyboard.Key key); 12759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 12859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 12959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int NOT_A_KEY = -1; 13059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE }; 13159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int[] LONG_PRESSABLE_STATE_SET = { 13259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.attr.state_long_pressable 13359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }; 13459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 13559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Keyboard mKeyboard; 13659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mCurrentKeyIndex = NOT_A_KEY; 13759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mLabelTextSize; 13859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mKeyTextSize; 13959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mKeyTextColor; 14059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mKeyTextColor2nd; 14159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private float mShadowRadius; 14259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mShadowColor; 14359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private float mBackgroundDimAmount; 14459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 14559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private TextView mPreviewText; 14659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private PopupWindow mPreviewPopup; 14759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mPreviewTextSizeLarge; 14859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mPreviewOffset; 14959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mPreviewHeight; 15059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int[] mOffsetInWindow; 15159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 15259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private PopupWindow mPopupKeyboard; 15359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private View mMiniKeyboardContainer; 15459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private KeyboardView mMiniKeyboard; 15559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mMiniKeyboardOnScreen; 15659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private View mPopupParent; 15759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mMiniKeyboardOffsetX; 15859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mMiniKeyboardOffsetY; 15959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Map<Key,View> mMiniKeyboardCache; 16059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int[] mWindowOffset; 16159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Key[] mKeys; 16259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 16359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Listener for {@link OnKeyboardActionListener}. */ 16459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private OnKeyboardActionListener mKeyboardActionListener; 16559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 16659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int MSG_SHOW_PREVIEW = 1; 16759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int MSG_REMOVE_PREVIEW = 2; 16859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int MSG_REPEAT = 3; 16959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int MSG_LONGPRESS = 4; 17059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 17159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int DELAY_BEFORE_PREVIEW = 0; 17259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int DELAY_AFTER_PREVIEW = 70; 17359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int DEBOUNCE_TIME = 70; 17459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 17559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mVerticalCorrection; 17659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mProximityThreshold; 17759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 17859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mPreviewCentered = false; 17959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mShowPreview = true; 18059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mShowTouchPoints = true; 18159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mPopupPreviewX; 18259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mPopupPreviewY; 18359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mWindowY; 18459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 18559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mLastX; 18659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mLastY; 18759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mStartX; 18859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mStartY; 18959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 19059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mProximityCorrectOn; 19159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 19259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Paint mPaint; 19359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Rect mPadding; 19459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 19559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private long mDownTime; 19659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private long mLastMoveTime; 19759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mLastKey; 19859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mLastCodeX; 19959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mLastCodeY; 20059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mCurrentKey = NOT_A_KEY; 20159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mDownKey = NOT_A_KEY; 20259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private long mLastKeyTime; 20359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private long mCurrentKeyTime; 20459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int[] mKeyIndices = new int[12]; 20559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private GestureDetector mGestureDetector; 20659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mPopupX; 20759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mPopupY; 20859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mRepeatKeyIndex = NOT_A_KEY; 20959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mPopupLayout; 21059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mAbortKey; 21159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Key mInvalidatedKey; 21259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Rect mClipRegion = new Rect(0, 0, 0, 0); 21359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mPossiblePoly; 21459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private SwipeTracker mSwipeTracker = new SwipeTracker(); 21559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mSwipeThreshold; 21659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mDisambiguateSwipe; 21759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 21859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mOldPointerCount = 1; 21959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private float mOldPointerX; 22059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private float mOldPointerY; 22159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 22259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Drawable mKeyBackground; 22359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Drawable mKeyBackground2nd; 22459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 22559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int REPEAT_INTERVAL = 50; 22659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int REPEAT_START_DELAY = 400; 22759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); 22859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 22959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static int MAX_NEARBY_KEYS = 12; 23059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int[] mDistances = new int[MAX_NEARBY_KEYS]; 23159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 23259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mLastSentIndex; 23359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int mTapCount; 23459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private long mLastTapTime; 23559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mInMultiTap; 23659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static final int MULTITAP_INTERVAL = 800; 23759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private StringBuilder mPreviewLabel = new StringBuilder(1); 23859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 23959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/ 24059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mDrawPending; 24159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** The dirty region in the keyboard bitmap */ 24259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Rect mDirtyRect = new Rect(); 24359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** The keyboard bitmap for faster updates */ 24459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Bitmap mBuffer; 24559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */ 24659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mKeyboardChanged; 24759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** The canvas for the above mutable keyboard bitmap */ 24859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private Canvas mCanvas; 24959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 25059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Handler mHandler = new Handler() { 25159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma @Override 25259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void handleMessage(Message msg) { 25359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma switch (msg.what) { 25459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case MSG_SHOW_PREVIEW: 25559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showKey(msg.arg1); 25659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 25759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case MSG_REMOVE_PREVIEW: 25859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setVisibility(INVISIBLE); 25959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 26059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case MSG_REPEAT: 26159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (repeatKey()) { 26259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Message repeat = Message.obtain(this, MSG_REPEAT); 26359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma sendMessageDelayed(repeat, REPEAT_INTERVAL); 26459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 26559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 26659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case MSG_LONGPRESS: 26759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma openPopupIfRequired((MotionEvent) msg.obj); 26859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 26959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 27059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 27159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }; 27259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 27359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Constructor */ 27459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public KeyboardView(Context context, AttributeSet attrs) { 27559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma this(context, attrs, 0); 27659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 27759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 27859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** Constructor */ 27959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public KeyboardView(Context context, AttributeSet attrs, int defStyle) { 28059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma super(context, attrs, defStyle); 28159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 28259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma TypedArray a = 28359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma context.obtainStyledAttributes( 28459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma attrs, android.R.styleable.KeyboardView, defStyle, R.style.WnnKeyboardView); 28559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 28659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma LayoutInflater inflate = 28759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma (LayoutInflater) context 28859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 28959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 29059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int previewLayout = 0; 29159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int keyTextSize = 0; 29259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 29359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int n = a.getIndexCount(); 29459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 29559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int i = 0; i < n; i++) { 29659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int attr = a.getIndex(i); 29759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 29859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma switch (attr) { 29959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_keyBackground: 30059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyBackground = a.getDrawable(attr); 30159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 30259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_verticalCorrection: 30359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mVerticalCorrection = a.getDimensionPixelOffset(attr, 0); 30459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 30559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_keyPreviewLayout: 30659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma previewLayout = a.getResourceId(attr, 0); 30759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 30859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_keyPreviewOffset: 30959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewOffset = a.getDimensionPixelOffset(attr, 0); 31059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 31159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_keyPreviewHeight: 31259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewHeight = a.getDimensionPixelSize(attr, 80); 31359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 31459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_keyTextSize: 31559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyTextSize = a.getDimensionPixelSize(attr, 18); 31659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 31759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_keyTextColor: 31859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyTextColor = a.getColor(attr, 0xFF000000); 31959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 32059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_labelTextSize: 32159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLabelTextSize = a.getDimensionPixelSize(attr, 14); 32259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 32359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_popupLayout: 32459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupLayout = a.getResourceId(attr, 0); 32559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 32659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_shadowColor: 32759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mShadowColor = a.getColor(attr, 0); 32859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 32959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case android.R.styleable.KeyboardView_shadowRadius: 33059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mShadowRadius = a.getFloat(attr, 0f); 33159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 33259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 33359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 33459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 33559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a.recycle(); 33659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a = context.obtainStyledAttributes(attrs, R.styleable.WnnKeyboardView, 0, 0); 33759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyBackground2nd = a.getDrawable(R.styleable.WnnKeyboardView_keyBackground2nd); 33859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyTextColor2nd = a.getColor(R.styleable.WnnKeyboardView_keyTextColor2nd, 0xFF000000); 33959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 34059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a.recycle(); 34159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma a = mContext.obtainStyledAttributes( 34259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma android.R.styleable.Theme); 34359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mBackgroundDimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f); 34459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 34559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewPopup = new PopupWindow(context); 34659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (previewLayout != 0) { 34759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText = (TextView) inflate.inflate(previewLayout, null); 34859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewTextSizeLarge = (int) mPreviewText.getTextSize(); 34959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewPopup.setContentView(mPreviewText); 35059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewPopup.setBackgroundDrawable(null); 35159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 35259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mShowPreview = false; 35359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 35459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 35559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewPopup.setTouchable(false); 35659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 35759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupKeyboard = new PopupWindow(context); 35859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupKeyboard.setBackgroundDrawable(null); 35959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 36059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupParent = this; 36159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 36259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPaint = new Paint(); 36359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPaint.setAntiAlias(true); 36459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPaint.setTextSize(keyTextSize); 36559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPaint.setTextAlign(Align.CENTER); 36659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPaint.setAlpha(255); 36759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 36859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPadding = new Rect(0, 0, 0, 0); 36959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardCache = new HashMap<Key,View>(); 37059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyBackground.getPadding(mPadding); 37159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 37259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density); 37359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 37459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDisambiguateSwipe = true; 37559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 37659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma resetMultiTap(); 37759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma initGestureDetector(); 37859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 37959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 38059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void initGestureDetector() { 38159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { 38259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma @Override 38359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean onFling(MotionEvent me1, MotionEvent me2, 38459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float velocityX, float velocityY) { 38559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mPossiblePoly) return false; 38659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float absX = Math.abs(velocityX); 38759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float absY = Math.abs(velocityY); 38859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float deltaX = me2.getX() - me1.getX(); 38959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float deltaY = me2.getY() - me1.getY(); 39059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int travelX = getWidth() / 2; 39159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int travelY = getHeight() / 2; 39259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mSwipeTracker.computeCurrentVelocity(1000); 39359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float endingVelocityX = mSwipeTracker.getXVelocity(); 39459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float endingVelocityY = mSwipeTracker.getYVelocity(); 39559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean sendDownKey = false; 39659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) { 39759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) { 39859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma sendDownKey = true; 39959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 40059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma swipeRight(); 40159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 40259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 40359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) { 40459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) { 40559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma sendDownKey = true; 40659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 40759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma swipeLeft(); 40859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 40959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 41059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) { 41159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) { 41259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma sendDownKey = true; 41359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 41459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma swipeUp(); 41559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 41659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 41759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) { 41859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) { 41959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma sendDownKey = true; 42059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 42159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma swipeDown(); 42259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 42359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 42459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 42559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 42659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (sendDownKey) { 42759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime()); 42859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 42959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 43059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 43159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }); 43259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 43359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mGestureDetector.setIsLongpressEnabled(false); 43459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 43559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 43659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 43759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Set the {@link OnKeyboardActionListener} object. 43859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param listener The OnKeyboardActionListener to set. 43959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 44059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { 44159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener = listener; 44259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 44359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 44459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 44559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the {@link OnKeyboardActionListener} object. 44659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return the listener attached to this keyboard 44759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 44859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected OnKeyboardActionListener getOnKeyboardActionListener() { 44959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mKeyboardActionListener; 45059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 45159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 45259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 45359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Attaches a keyboard to this view. The keyboard can be switched at any time and the 45459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * view will re-layout itself to accommodate the keyboard. 45559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see Keyboard 45659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #getKeyboard() 45759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param keyboard the keyboard to display in this view 45859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 45959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void setKeyboard(Keyboard keyboard) { 46059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (!keyboard.equals(mKeyboard)) { 46159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma clearWindowInfo(); 46259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 46359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int oldRepeatKeyCode = NOT_A_KEY; 46459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeyboard != null) { 46559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showPreview(NOT_A_KEY); 46659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if ((mRepeatKeyIndex != NOT_A_KEY) && (mRepeatKeyIndex < mKeys.length)) { 46759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma oldRepeatKeyCode = mKeys[mRepeatKeyIndex].codes[0]; 46859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 46959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 47059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma removeMessages(); 47159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboard = keyboard; 47259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma List<Key> keys = mKeyboard.getKeys(); 47359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeys = keys.toArray(new Key[keys.size()]); 47459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma requestLayout(); 47559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardChanged = true; 47659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateAllKeys(); 47759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma computeProximityThreshold(keyboard); 47859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardCache.clear(); 47959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean abort = true; 48059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (oldRepeatKeyCode != NOT_A_KEY) { 48159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int keyIndex = getKeyIndices(mStartX, mStartY, null); 48259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if ((keyIndex != NOT_A_KEY) 48359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && (keyIndex < mKeys.length) 48459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && (oldRepeatKeyCode == mKeys[keyIndex].codes[0])) { 48559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma abort = false; 48659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mRepeatKeyIndex = keyIndex; 48759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 48859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 48959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (abort) { 49059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_REPEAT); 49159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 49259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mAbortKey = abort; 49359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 49459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 49559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 49659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the current keyboard being displayed by this view. 49759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return the currently attached keyboard 49859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #setKeyboard(Keyboard) 49959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 50059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public Keyboard getKeyboard() { 50159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mKeyboard; 50259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 50359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 50459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 50559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Sets the state of the shift key of the keyboard, if any. 50659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param shifted whether or not to enable the state of the shift key 50759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return true if the shift key state changed, false if there was no change 50859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see KeyboardView#isShifted() 50959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 51059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean setShifted(boolean shifted) { 51159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeyboard != null) { 51259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeyboard.setShifted(shifted)) { 51359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateAllKeys(); 51459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 51559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 51659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 51759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 51859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 51959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 52059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 52159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the state of the shift key of the keyboard, if any. 52259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return true if the shift is in a pressed state, false otherwise. If there is 52359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * no shift key on the keyboard or there is no keyboard attached, it returns false. 52459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see KeyboardView#setShifted(boolean) 52559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 52659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean isShifted() { 52759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeyboard != null) { 52859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mKeyboard.isShifted(); 52959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 53059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 53159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 53259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 53359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 53459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Enables or disables the key feedback popup. This is a popup that shows a magnified 53559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * version of the depressed key. By default the preview is enabled. 53659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param previewEnabled whether or not to enable the key feedback popup 53759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #isPreviewEnabled() 53859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 53959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void setPreviewEnabled(boolean previewEnabled) { 54059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mShowPreview = previewEnabled; 54159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 54259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 54359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 54459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the enabled state of the key feedback popup. 54559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return whether or not the key feedback popup is enabled 54659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #setPreviewEnabled(boolean) 54759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 54859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean isPreviewEnabled() { 54959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mShowPreview; 55059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 55159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 55259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 55359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns the root parent has the enabled state of the key feedback popup. 55459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return whether or not the key feedback popup is enabled 55559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #setPreviewEnabled(boolean) 55659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 55759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean isParentPreviewEnabled() { 55859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if ((mPopupParent != null) && (mPopupParent != this) 55959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && (mPopupParent instanceof KeyboardView)) { 56059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return ((KeyboardView)mPopupParent).isParentPreviewEnabled(); 56159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 56259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mShowPreview; 56359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 56459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 56559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 56659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void setVerticalCorrection(int verticalOffset) { 56759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 56859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 56959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 57059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 57159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Set View on the PopupParent. 57259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param v The View to set. 57359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 57459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void setPopupParent(View v) { 57559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupParent = v; 57659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 57759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 57859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 57959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Set parameters on the KeyboardOffset. 58059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param x The value of KeyboardOffset. 58159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param y The value of KeyboardOffset. 58259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 58359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void setPopupOffset(int x, int y) { 58459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardOffsetX = x; 58559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardOffsetY = y; 58659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mPreviewPopup.isShowing()) { 58759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewPopup.dismiss(); 58859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 58959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 59059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 59159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 59259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * When enabled, calls to {@link OnKeyboardActionListener#onKey} will include key 59359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * codes for adjacent keys. When disabled, only the primary key code will be 59459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * reported. 59559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param enabled whether or not the proximity correction is enabled 59659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 59759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void setProximityCorrectionEnabled(boolean enabled) { 59859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mProximityCorrectOn = enabled; 59959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 60059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 60159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 60259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Returns true if proximity correction is enabled. 60359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 60459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean isProximityCorrectionEnabled() { 60559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mProximityCorrectOn; 60659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 60759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 60859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 60959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Popup keyboard close button clicked. 61059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @hide 61159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 61259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onClick(View v) { 61359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma dismissPopupKeyboard(); 61459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 61559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 61659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private CharSequence adjustCase(CharSequence label) { 61759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeyboard.isShifted() && label != null && label.length() < 3 61859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && Character.isLowerCase(label.charAt(0))) { 61959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma label = label.toString().toUpperCase(); 62059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 62159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return label; 62259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 62359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 62459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma @Override 62559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 62659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeyboard == null) { 62759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma setMeasuredDimension(mPaddingLeft + mPaddingRight, mPaddingTop + mPaddingBottom); 62859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 62959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int width = mKeyboard.getMinWidth() + mPaddingLeft + mPaddingRight; 63059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) { 63159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma width = MeasureSpec.getSize(widthMeasureSpec); 63259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 63359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma setMeasuredDimension(width, mKeyboard.getHeight() + mPaddingTop + mPaddingBottom); 63459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 63559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 63659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 63759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 63859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Compute the average distance between adjacent keys (horizontally and vertically) 63959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * and square it to get the proximity threshold. We use a square here and in computing 64059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * the touch distance from a key's center to avoid taking a square root. 64159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param keyboard 64259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 64359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void computeProximityThreshold(Keyboard keyboard) { 64459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyboard == null) return; 64559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key[] keys = mKeys; 64659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keys == null) return; 64759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int length = keys.length; 64859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int dimensionSum = 0; 64959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int i = 0; i < length; i++) { 65059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Key key = keys[i]; 65159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma dimensionSum += Math.min(key.width, key.height) + key.gap; 65259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 65359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (dimensionSum < 0 || length == 0) return; 65459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mProximityThreshold = (int) (dimensionSum * 1.4f / length); 65559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mProximityThreshold *= mProximityThreshold; 65659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 65759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 65859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma @Override 65959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onSizeChanged(int w, int h, int oldw, int oldh) { 66059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma super.onSizeChanged(w, h, oldw, oldh); 66159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mBuffer = null; 66259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 66359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 66459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma @Override 66559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onDraw(Canvas canvas) { 66659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma super.onDraw(canvas); 66759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mDrawPending || mBuffer == null || mKeyboardChanged) { 66859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma onBufferDraw(); 66959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 67059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.drawBitmap(mBuffer, 0, 0, null); 67159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 67259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 67359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void onBufferDraw() { 67459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean isBufferNull = (mBuffer == null); 67559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (isBufferNull || mKeyboardChanged) { 67659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (isBufferNull || mKeyboardChanged && 67759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) { 67859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int width = Math.max(1, getWidth()); 67959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int height = Math.max(1, getHeight()); 68059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 68159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCanvas = new Canvas(mBuffer); 68259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 68359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateAllKeys(); 68459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardChanged = false; 68559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 68659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Canvas canvas = mCanvas; 68759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.clipRect(mDirtyRect, Op.REPLACE); 68859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 68959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeyboard == null) return; 69059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 69159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Paint paint = mPaint; 69259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Rect clipRegion = mClipRegion; 69359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Rect padding = mPadding; 69459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int kbdPaddingLeft = mPaddingLeft; 69559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int kbdPaddingTop = mPaddingTop; 69659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key[] keys = mKeys; 69759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key invalidKey = mInvalidatedKey; 69859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 69959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setColor(mKeyTextColor); 70059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean drawSingleKey = false; 70159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (invalidKey != null && canvas.getClipBounds(clipRegion)) { 70259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left && 70359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top && 70459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right && 70559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) { 70659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma drawSingleKey = true; 70759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 70859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 70959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); 71059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int keyCount = keys.length; 71159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int i = 0; i < keyCount; i++) { 71259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key key = keys[i]; 71359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (drawSingleKey && invalidKey != key) { 71459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma continue; 71559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 71659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 71759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setColor(key.isSecondKey ? mKeyTextColor2nd : mKeyTextColor); 71859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Drawable keyBackground = key.isSecondKey ? mKeyBackground2nd : mKeyBackground; 71959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int[] drawableState = key.getCurrentDrawableState(); 72059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyBackground.setState(drawableState); 72159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 72259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma String label = key.label == null? null : adjustCase(key.label).toString(); 72359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 72459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Rect bounds = keyBackground.getBounds(); 72559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (key.width != bounds.right || 72659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.height != bounds.bottom) { 72759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyBackground.setBounds(0, 0, key.width, key.height); 72859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 72959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop); 73059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyBackground.draw(canvas); 73159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 73259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (label != null) { 73359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (OpenWnn.isXLarge()) { 73459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (label.length() > 1 && key.codes.length < 2) { 73559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setTextSize(mLabelTextSize); 73659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setTypeface(Typeface.DEFAULT); 73759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 73859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setTextSize(mKeyTextSize); 73959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setTypeface(Typeface.DEFAULT_BOLD); 74059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 74159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 74259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (label.length() > 1 && key.codes.length < 2) { 74359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setTextSize(mLabelTextSize); 74459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setTypeface(Typeface.DEFAULT_BOLD); 74559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 74659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setTextSize(mKeyTextSize); 74759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setTypeface(Typeface.DEFAULT_BOLD); 74859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 74959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 75059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor); 75159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (OpenWnn.isXLarge()) { 75259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.drawText(label, 75359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma (key.width - padding.left + 7 - padding.right) / 2 75459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma + padding.left, 75559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma (key.height - padding.top + 7 - padding.bottom) / 2 75659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma + (paint.getTextSize() - paint.descent()) / 2 + padding.top, 75759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint); 75859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 75959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.drawText(label, 76059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma (key.width - padding.left - padding.right) / 2 76159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma + padding.left, 76259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma (key.height - padding.top - padding.bottom) / 2 76359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma + (paint.getTextSize() - paint.descent()) / 2 + padding.top, 76459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint); 76559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 76659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setShadowLayer(0, 0, 0, 0); 76759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (key.icon != null) { 76859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int drawableX; 76959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int drawableY; 77059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (OpenWnn.isXLarge()) { 77159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma drawableX = (key.width - padding.left + 12 - padding.right 77259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma - key.icon.getIntrinsicWidth()) / 2 + padding.left; 77359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma drawableY = (key.height - padding.top + 9 - padding.bottom 77459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma - key.icon.getIntrinsicHeight()) / 2 + padding.top; 77559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 77659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma drawableX = (key.width - padding.left - padding.right 77759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma - key.icon.getIntrinsicWidth()) / 2 + padding.left; 77859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma drawableY = (key.height - padding.top - padding.bottom 77959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma - key.icon.getIntrinsicHeight()) / 2 + padding.top; 78059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 78159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.translate(drawableX, drawableY); 78259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.icon.setBounds(0, 0, 78359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight()); 78459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.icon.draw(canvas); 78559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.translate(-drawableX, -drawableY); 78659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 78759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop); 78859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 78959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mInvalidatedKey = null; 79059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mMiniKeyboardOnScreen) { 79159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); 79259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma canvas.drawRect(0, 0, getWidth(), getHeight(), paint); 79359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 79459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 79559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDrawPending = false; 79659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDirtyRect.setEmpty(); 79759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 79859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 79959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private int getKeyIndices(int x, int y, int[] allKeys) { 80059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key[] keys = mKeys; 80159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int primaryIndex = NOT_A_KEY; 80259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int closestKey = NOT_A_KEY; 80359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int closestKeyDist = mProximityThreshold + 1; 80459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma java.util.Arrays.fill(mDistances, Integer.MAX_VALUE); 80559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); 80659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int keyCount = nearestKeyIndices.length; 80759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int i = 0; i < keyCount; i++) { 80859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key key = keys[nearestKeyIndices[i]]; 80959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int dist = 0; 81059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean isInside = key.isInside(x,y); 81159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (isInside) { 81259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma primaryIndex = nearestKeyIndices[i]; 81359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 81459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 81559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (((mProximityCorrectOn 81659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold) 81759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma || isInside) 81859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && key.codes[0] > 32) { 81959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int nCodes = key.codes.length; 82059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (dist < closestKeyDist) { 82159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma closestKeyDist = dist; 82259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma closestKey = nearestKeyIndices[i]; 82359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 82459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 82559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (allKeys == null) continue; 82659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 82759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int j = 0; j < mDistances.length; j++) { 82859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mDistances[j] > dist) { 82959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma System.arraycopy(mDistances, j, mDistances, j + nCodes, 83059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDistances.length - j - nCodes); 83159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma System.arraycopy(allKeys, j, allKeys, j + nCodes, 83259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma allKeys.length - j - nCodes); 83359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int c = 0; c < nCodes; c++) { 83459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma allKeys[j + c] = key.codes[c]; 83559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDistances[j + c] = dist; 83659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 83759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 83859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 83959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 84059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 84159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 84259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (primaryIndex == NOT_A_KEY) { 84359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma primaryIndex = closestKey; 84459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 84559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return primaryIndex; 84659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 84759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 84859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void detectAndSendKey(int index, int x, int y, long eventTime) { 84959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (index != NOT_A_KEY && index < mKeys.length) { 85059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key key = mKeys[index]; 85159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (key.text != null) { 85259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onText(key.text); 85359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onRelease(NOT_A_KEY); 85459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 85559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int code = key.codes[0]; 85659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int[] codes = new int[MAX_NEARBY_KEYS]; 85759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Arrays.fill(codes, NOT_A_KEY); 85859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma getKeyIndices(x, y, codes); 85959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mInMultiTap) { 86059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mTapCount != -1) { 86159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE); 86259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 86359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTapCount = 0; 86459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 86559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma code = key.codes[mTapCount]; 86659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 86759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onKey(code, codes); 86859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onRelease(code); 86959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 87059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastSentIndex = index; 87159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastTapTime = eventTime; 87259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 87359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 87459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 87559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 87659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Handle multi-tap keys by producing the key label for the current multi-tap state. 87759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 87859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private CharSequence getPreviewText(Key key) { 87959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mInMultiTap) { 88059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewLabel.setLength(0); 88159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]); 88259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return adjustCase(mPreviewLabel); 88359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 88459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return adjustCase(key.label); 88559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 88659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 88759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 88859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void showPreview(int keyIndex) { 88959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int oldKeyIndex = mCurrentKeyIndex; 89059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final PopupWindow previewPopup = mPreviewPopup; 89159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 89259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKeyIndex = keyIndex; 89359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key[] keys = mKeys; 89459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (oldKeyIndex != mCurrentKeyIndex) { 89559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) { 89659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keys[oldKeyIndex].onReleased(mCurrentKeyIndex == NOT_A_KEY); 89759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateKey(oldKeyIndex); 89859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 89959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) { 90059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keys[mCurrentKeyIndex].onPressed(); 90159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateKey(mCurrentKeyIndex); 90259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 90359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 90459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (oldKeyIndex != mCurrentKeyIndex && mShowPreview && isParentPreviewEnabled()) { 90559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_SHOW_PREVIEW); 90659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (previewPopup.isShowing()) { 90759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex == NOT_A_KEY) { 90859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.sendMessageDelayed(mHandler 90959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma .obtainMessage(MSG_REMOVE_PREVIEW), 91059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma DELAY_AFTER_PREVIEW); 91159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 91259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 91359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex != NOT_A_KEY) { 91459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { 91559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showKey(keyIndex); 91659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 91759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.sendMessageDelayed( 91859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0), 91959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma DELAY_BEFORE_PREVIEW); 92059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 92159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 92259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 92359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 92459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 92559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void showKey(final int keyIndex) { 92659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final PopupWindow previewPopup = mPreviewPopup; 92759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key[] keys = mKeys; 92859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex < 0 || keyIndex >= mKeys.length) return; 92959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Key key = keys[keyIndex]; 93059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 93159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setBackgroundDrawable(getContext().getResources().getDrawable(R.drawable.keyboard_key_feedback)); 93259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 93359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (key.icon != null) { 93459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setCompoundDrawables(null, null, null, 93559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.iconPreview != null ? key.iconPreview : key.icon); 93659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setText(null); 93759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setPadding(5, 0, 5, 20); 93859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 93959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setCompoundDrawables(null, null, null, null); 94059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setText(getPreviewText(key)); 94159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (key.label.length() > 1 && key.codes.length < 2) { 94259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize); 94359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); 94459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 94559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge); 94659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setTypeface(Typeface.DEFAULT); 94759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 94859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setPadding(0, 0, 0, 10); 94959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 95059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 95159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 95259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width 95359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight()); 95459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int popupHeight = mPreviewHeight; 95559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma LayoutParams lp = mPreviewText.getLayoutParams(); 95659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (lp != null) { 95759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma lp.width = popupWidth; 95859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma lp.height = popupHeight; 95959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 96059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (!mPreviewCentered) { 96159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewX = key.x - (Math.abs(popupWidth - key.width) / 2 ); 96259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewY = key.y - popupHeight + mPreviewOffset; 96359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 96459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2; 96559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewY = - mPreviewText.getMeasuredHeight(); 96659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 96759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewY = mPopupPreviewY + 20; 96859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_REMOVE_PREVIEW); 96959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mOffsetInWindow == null) { 97059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOffsetInWindow = new int[2]; 97159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma getLocationInWindow(mOffsetInWindow); 97259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOffsetInWindow[0] += mMiniKeyboardOffsetX; 97359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOffsetInWindow[1] += mMiniKeyboardOffsetY; 97459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int[] mWindowLocation = new int[2]; 97559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma getLocationOnScreen(mWindowLocation); 97659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mWindowY = mWindowLocation[1]; 97759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 97859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.getBackground().setState( 97959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET); 98059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewX += mOffsetInWindow[0]; 98159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewY += mOffsetInWindow[1]; 98259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 98359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mPopupPreviewY + mWindowY < 0) { 98459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (key.x + key.width <= getWidth() / 2) { 98559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewX += (int) (key.width * 2.5); 98659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 98759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewX -= (int) (key.width * 2.5); 98859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 98959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewY += popupHeight; 99059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 99159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 99259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (previewPopup.isShowing()) { 99359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma previewPopup.update(mPopupPreviewX, mPopupPreviewY, 99459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma popupWidth, popupHeight); 99559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 99659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma previewPopup.setWidth(popupWidth); 99759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma previewPopup.setHeight(popupHeight); 99859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, 99959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupPreviewX, mPopupPreviewY); 100059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 100159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewText.setVisibility(VISIBLE); 100259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 100359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 100459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 100559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient 100659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * because the keyboard renders the keys to an off-screen buffer and an invalidate() only 100759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * draws the cached buffer. 100859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #invalidateKey(int) 100959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 101059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void invalidateAllKeys() { 101159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDirtyRect.union(0, 0, getWidth(), getHeight()); 101259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDrawPending = true; 101359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidate(); 101459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 101559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 101659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 101759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Invalidates a key so that it will be redrawn on the next repaint. Use this method if only 101859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * one key is changing it's content. Any changes that affect the position or size of the key 101959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * may not be honored. 102059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param keyIndex the index of the key in the attached {@link Keyboard}. 102159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @see #invalidateAllKeys 102259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 102359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void invalidateKey(int keyIndex) { 102459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeys == null) return; 102559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex < 0 || keyIndex >= mKeys.length) { 102659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return; 102759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 102859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final Key key = mKeys[keyIndex]; 102959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mInvalidatedKey = key; 103059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDirtyRect.union(key.x + mPaddingLeft, key.y + mPaddingTop, 103159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop); 103259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma onBufferDraw(); 103359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidate(key.x + mPaddingLeft, key.y + mPaddingTop, 103459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop); 103559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 103659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 103759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean openPopupIfRequired(MotionEvent me) { 103859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mPopupLayout == 0) { 103959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 104059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 104159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mCurrentKey < 0 || mCurrentKey >= mKeys.length) { 104259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 104359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 104459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 104559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Key popupKey = mKeys[mCurrentKey]; 104659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean result = onLongPress(popupKey); 104759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (result) { 104859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mAbortKey = true; 104959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showPreview(NOT_A_KEY); 105059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 105159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return result; 105259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 105359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 105459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 105559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Called when a key is long pressed. By default this will open any popup keyboard associated 105659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * with this key through the attributes popupLayout and popupCharacters. 105759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @param popupKey the key that was long pressed 105859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * @return true if the long press is handled, false otherwise. Subclasses should call the 105959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * method on the base class if the subclass doesn't wish to handle the call. 106059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 106159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected boolean onLongPress(Key popupKey) { 106259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mKeyboardActionListener.onLongPress(popupKey)) { 106359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 106459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 106559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int popupKeyboardId = popupKey.popupResId; 106659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (popupKeyboardId != 0) { 106759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey); 106859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mMiniKeyboardContainer == null) { 106959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 107059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Context.LAYOUT_INFLATER_SERVICE); 107159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null); 107259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById(R.id.keyboardView); 107359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma View closeButton = mMiniKeyboardContainer.findViewById(R.id.closeButton); 107459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (closeButton != null) closeButton.setOnClickListener(this); 107559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { 107659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onKey(int primaryCode, int[] keyCodes) { 107759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onKey(primaryCode, keyCodes); 107859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma dismissPopupKeyboard(); 107959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 108059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 108159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onText(CharSequence text) { 108259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onText(text); 108359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma dismissPopupKeyboard(); 108459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 108559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 108659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void swipeLeft() { } 108759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void swipeRight() { } 108859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void swipeUp() { } 108959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void swipeDown() { } 109059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onPress(int primaryCode) { 109159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onPress(primaryCode); 109259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 109359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onRelease(int primaryCode) { 109459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onRelease(primaryCode); 109559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 109659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean onLongPress(Keyboard.Key key) { 109759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 109859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 109959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma }); 110059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Keyboard keyboard; 110159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (popupKey.popupCharacters != null) { 110259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyboard = new Keyboard(getContext(), popupKeyboardId, 110359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight()); 110459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 110559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma keyboard = new Keyboard(getContext(), popupKeyboardId); 110659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 110759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboard.setKeyboard(keyboard); 110859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboard.setPopupParent(this); 110959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardContainer.measure( 111059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), 111159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); 111259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 111359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer); 111459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 111559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById(R.id.keyboardView); 111659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 111759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mWindowOffset == null) { 111859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mWindowOffset = new int[2]; 111959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma getLocationInWindow(mWindowOffset); 112059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 112159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupX = popupKey.x + mPaddingLeft; 112259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupY = popupKey.y + mPaddingTop; 112359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth(); 112459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight(); 112559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mWindowOffset[0]; 112659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mWindowOffset[1]; 112759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y); 112859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboard.setShifted(isShifted()); 112959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupKeyboard.setContentView(mMiniKeyboardContainer); 113059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth()); 113159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight()); 113259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y); 113359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardOnScreen = true; 113459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateAllKeys(); 113559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 113659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 113759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 113859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 113959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 114059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private long mOldEventTime; 114159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean mUsedVelocity; 114259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 114359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma @Override 114459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean onTouchEvent(MotionEvent me) { 114559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int pointerCount = me.getPointerCount(); 114659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int action = me.getAction(); 114759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean result = false; 114859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final long now = me.getEventTime(); 114959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final boolean isPointerCountOne = (pointerCount == 1); 115059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 115159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (pointerCount != mOldPointerCount) { 115259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (isPointerCountOne) { 115359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 115459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma me.getX(), me.getY(), me.getMetaState()); 115559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma result = onModifiedTouchEvent(down, false); 115659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma down.recycle(); 115759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (action == MotionEvent.ACTION_UP) { 115859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma result = onModifiedTouchEvent(me, true); 115959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 116059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 116159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 116259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOldPointerX, mOldPointerY, me.getMetaState()); 116359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma result = onModifiedTouchEvent(up, true); 116459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma up.recycle(); 116559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 116659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 116759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (isPointerCountOne) { 116859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma result = onModifiedTouchEvent(me, false); 116959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOldPointerX = me.getX(); 117059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOldPointerY = me.getY(); 117159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 117259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma result = true; 117359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 117459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 117559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOldPointerCount = pointerCount; 117659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 117759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return result; 117859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 117959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 118059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean onModifiedTouchEvent(MotionEvent me, boolean possiblePoly) { 118159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int touchX = (int) me.getX() - mPaddingLeft; 118259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int touchY = (int) me.getY() + mVerticalCorrection - mPaddingTop; 118359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int action = me.getAction(); 118459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final long eventTime = me.getEventTime(); 118559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOldEventTime = eventTime; 118659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int keyIndex = getKeyIndices(touchX, touchY, null); 118759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPossiblePoly = possiblePoly; 118859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 118959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (action == MotionEvent.ACTION_DOWN) mSwipeTracker.clear(); 119059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mSwipeTracker.addMovement(me); 119159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 119259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mAbortKey 119359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) { 119459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 119559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 119659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 119759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mGestureDetector.onTouchEvent(me)) { 119859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showPreview(NOT_A_KEY); 119959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_REPEAT); 120059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_LONGPRESS); 120159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 120259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 120359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 120459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) { 120559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 120659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 120759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 120859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma switch (action) { 120959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case MotionEvent.ACTION_DOWN: 121059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mAbortKey = false; 121159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mStartX = touchX; 121259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mStartY = touchY; 121359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastCodeX = touchX; 121459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastCodeY = touchY; 121559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastKeyTime = 0; 121659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKeyTime = 0; 121759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastKey = NOT_A_KEY; 121859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKey = keyIndex; 121959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDownKey = keyIndex; 122059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mDownTime = me.getEventTime(); 122159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastMoveTime = mDownTime; 122259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma checkMultiTap(eventTime, keyIndex); 122359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ? 122459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeys[keyIndex].codes[0] : 0); 122559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) { 122659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mRepeatKeyIndex = mCurrentKey; 122759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Message msg = mHandler.obtainMessage(MSG_REPEAT); 122859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY); 122959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma repeatKey(); 123059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mAbortKey) { 123159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mRepeatKeyIndex = NOT_A_KEY; 123259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 123359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 123459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 123559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mCurrentKey != NOT_A_KEY) { 123659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me); 123759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT); 123859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 123959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showPreview(keyIndex); 124059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 124159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 124259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case MotionEvent.ACTION_MOVE: 124359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma boolean continueLongPress = false; 124459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex != NOT_A_KEY) { 124559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mCurrentKey == NOT_A_KEY) { 124659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKey = keyIndex; 124759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKeyTime = eventTime - mDownTime; 124859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 124959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex == mCurrentKey) { 125059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKeyTime += eventTime - mLastMoveTime; 125159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma continueLongPress = true; 125259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (mRepeatKeyIndex == NOT_A_KEY) { 125359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma resetMultiTap(); 125459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastKey = mCurrentKey; 125559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastCodeX = mLastX; 125659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastCodeY = mLastY; 125759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastKeyTime = 125859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKeyTime + eventTime - mLastMoveTime; 125959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKey = keyIndex; 126059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKeyTime = 0; 126159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 126259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 126359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 126459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (!continueLongPress) { 126559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_LONGPRESS); 126659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex != NOT_A_KEY) { 126759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me); 126859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT); 126959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 127059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 127159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showPreview(mCurrentKey); 127259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastMoveTime = eventTime; 127359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 127459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 127559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case MotionEvent.ACTION_UP: 127659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma removeMessages(); 127759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex == mCurrentKey) { 127859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKeyTime += eventTime - mLastMoveTime; 127959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 128059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma resetMultiTap(); 128159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastKey = mCurrentKey; 128259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime; 128359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKey = keyIndex; 128459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKeyTime = 0; 128559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 128659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < DEBOUNCE_TIME 128759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && mLastKey != NOT_A_KEY) { 128859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCurrentKey = mLastKey; 128959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma touchX = mLastCodeX; 129059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma touchY = mLastCodeY; 129159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 129259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showPreview(NOT_A_KEY); 129359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Arrays.fill(mKeyIndices, NOT_A_KEY); 129459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) { 129559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma detectAndSendKey(mCurrentKey, touchX, touchY, eventTime); 129659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 129759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateKey(keyIndex); 129859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mRepeatKeyIndex = NOT_A_KEY; 129959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 130059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma case MotionEvent.ACTION_CANCEL: 130159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma removeMessages(); 130259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma dismissPopupKeyboard(); 130359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mAbortKey = true; 130459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma showPreview(NOT_A_KEY); 130559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateKey(mCurrentKey); 130659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 130759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 130859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastX = touchX; 130959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastY = touchY; 131059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 131159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 131259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 131359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private boolean repeatKey() { 131459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Key key = mKeys[mRepeatKeyIndex]; 131559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime); 131659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 131759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 131859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 131959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected void swipeRight() { 132059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.swipeRight(); 132159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 132259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 132359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected void swipeLeft() { 132459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.swipeLeft(); 132559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 132659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 132759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected void swipeUp() { 132859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.swipeUp(); 132959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 133059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 133159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma protected void swipeDown() { 133259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mKeyboardActionListener.swipeDown(); 133359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 133459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 133559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void closing() { 133659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mPreviewPopup.isShowing()) { 133759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPreviewPopup.dismiss(); 133859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 133959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma removeMessages(); 134059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 134159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma dismissPopupKeyboard(); 134259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mBuffer = null; 134359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mCanvas = null; 134459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardCache.clear(); 134559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 134659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 134759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void removeMessages() { 134859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_REPEAT); 134959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_LONGPRESS); 135059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mHandler.removeMessages(MSG_SHOW_PREVIEW); 135159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 135259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 135359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma @Override 135459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void onDetachedFromWindow() { 135559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma super.onDetachedFromWindow(); 135659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma closing(); 135759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 135859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 135959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void dismissPopupKeyboard() { 136059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mPopupKeyboard.isShowing()) { 136159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPopupKeyboard.dismiss(); 136259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mMiniKeyboardOnScreen = false; 136359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma invalidateAllKeys(); 136459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 136559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 136659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 136759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public boolean handleBack() { 136859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (mPopupKeyboard.isShowing()) { 136959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma dismissPopupKeyboard(); 137059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return true; 137159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 137259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return false; 137359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 137459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 137559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void resetMultiTap() { 137659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastSentIndex = NOT_A_KEY; 137759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTapCount = 0; 137859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mLastTapTime = -1; 137959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mInMultiTap = false; 138059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 138159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 138259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void checkMultiTap(long eventTime, int keyIndex) { 138359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (keyIndex == NOT_A_KEY) return; 138459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma Key key = mKeys[keyIndex]; 138559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (key.codes.length > 1) { 138659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mInMultiTap = true; 138759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (eventTime < mLastTapTime + MULTITAP_INTERVAL 138859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma && keyIndex == mLastSentIndex) { 138959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTapCount = (mTapCount + 1) % key.codes.length; 139059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return; 139159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else { 139259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mTapCount = -1; 139359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return; 139459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 139559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 139659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) { 139759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma resetMultiTap(); 139859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 139959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 140059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 140159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private static class SwipeTracker { 140259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 140359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma static final int NUM_PAST = 4; 140459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma static final int LONGEST_PAST_TIME = 200; 140559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 140659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float mPastX[] = new float[NUM_PAST]; 140759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float mPastY[] = new float[NUM_PAST]; 140859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final long mPastTime[] = new long[NUM_PAST]; 140959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 141059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float mYVelocity; 141159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float mXVelocity; 141259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 141359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void clear() { 141459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mPastTime[0] = 0; 141559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 141659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 141759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void addMovement(MotionEvent ev) { 141859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma long time = ev.getEventTime(); 141959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int N = ev.getHistorySize(); 142059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int i=0; i<N; i++) { 142159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i), 142259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma ev.getHistoricalEventTime(i)); 142359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 142459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma addPoint(ev.getX(), ev.getY(), time); 142559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 142659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 142759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma private void addPoint(float x, float y, long time) { 142859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int drop = -1; 142959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int i; 143059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final long[] pastTime = mPastTime; 143159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (i=0; i<NUM_PAST; i++) { 143259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (pastTime[i] == 0) { 143359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 143459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } else if (pastTime[i] < time-LONGEST_PAST_TIME) { 143559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma drop = i; 143659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 143759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 143859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (i == NUM_PAST && drop < 0) { 143959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma drop = 0; 144059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 144159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (drop == i) drop--; 144259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float[] pastX = mPastX; 144359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float[] pastY = mPastY; 144459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (drop >= 0) { 144559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int start = drop+1; 144659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int count = NUM_PAST-drop-1; 144759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma System.arraycopy(pastX, start, pastX, 0, count); 144859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma System.arraycopy(pastY, start, pastY, 0, count); 144959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma System.arraycopy(pastTime, start, pastTime, 0, count); 145059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma i -= (drop+1); 145159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 145259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma pastX[i] = x; 145359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma pastY[i] = y; 145459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma pastTime[i] = time; 145559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma i++; 145659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (i < NUM_PAST) { 145759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma pastTime[i] = 0; 145859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 145959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 146059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 146159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void computeCurrentVelocity(int units) { 146259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma computeCurrentVelocity(units, Float.MAX_VALUE); 146359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 146459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 146559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void computeCurrentVelocity(int units, float maxVelocity) { 146659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float[] pastX = mPastX; 146759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float[] pastY = mPastY; 146859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final long[] pastTime = mPastTime; 146959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 147059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float oldestX = pastX[0]; 147159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final float oldestY = pastY[0]; 147259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final long oldestTime = pastTime[0]; 147359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float accumX = 0; 147459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float accumY = 0; 147559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma int N=0; 147659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma while (N < NUM_PAST) { 147759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (pastTime[N] == 0) { 147859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma break; 147959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 148059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma N++; 148159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 148259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 148359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma for (int i=1; i < N; i++) { 148459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma final int dur = (int)(pastTime[i] - oldestTime); 148559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (dur == 0) continue; 148659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float dist = pastX[i] - oldestX; 148759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma float vel = (dist/dur) * units; 148859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (accumX == 0) accumX = vel; 148959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma else accumX = (accumX + vel) * .5f; 149059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 149159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma dist = pastY[i] - oldestY; 149259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma vel = (dist/dur) * units; 149359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma if (accumY == 0) accumY = vel; 149459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma else accumY = (accumY + vel) * .5f; 149559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 149659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) 149759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma : Math.min(accumX, maxVelocity); 149859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) 149959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma : Math.min(accumY, maxVelocity); 150059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 150159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 150259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public float getXVelocity() { 150359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mXVelocity; 150459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 150559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 150659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public float getYVelocity() { 150759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma return mYVelocity; 150859aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 150959aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 151059aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma 151159aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma /** 151259aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma * Clear window info. 151359aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma */ 151459aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma public void clearWindowInfo() { 151559aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma mOffsetInWindow = null; 151659aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma } 151759aefa242169b7a51c2381daee58ff22fd1834ceJunichi Monma} 1518