FileDocCategorySizeDatePackage
KeyboardView.javaAPI DocAndroid 5.1 API62857Thu Mar 12 22:22:10 GMT 2015android.inputmethodservice

KeyboardView

public class KeyboardView extends android.view.View implements View.OnClickListener
A view that renders a virtual {@link Keyboard}. It handles rendering of keys and detecting key presses and touch movements.
attr
ref android.R.styleable#KeyboardView_keyBackground
attr
ref android.R.styleable#KeyboardView_keyPreviewLayout
attr
ref android.R.styleable#KeyboardView_keyPreviewOffset
attr
ref android.R.styleable#KeyboardView_labelTextSize
attr
ref android.R.styleable#KeyboardView_keyTextSize
attr
ref android.R.styleable#KeyboardView_keyTextColor
attr
ref android.R.styleable#KeyboardView_verticalCorrection
attr
ref android.R.styleable#KeyboardView_popupLayout

Fields Summary
private static final boolean
DEBUG
private static final int
NOT_A_KEY
private static final int[]
KEY_DELETE
private static final int[]
LONG_PRESSABLE_STATE_SET
private Keyboard
mKeyboard
private int
mCurrentKeyIndex
private int
mLabelTextSize
private int
mKeyTextSize
private int
mKeyTextColor
private float
mShadowRadius
private int
mShadowColor
private float
mBackgroundDimAmount
private android.widget.TextView
mPreviewText
private android.widget.PopupWindow
mPreviewPopup
private int
mPreviewTextSizeLarge
private int
mPreviewOffset
private int
mPreviewHeight
private final int[]
mCoordinates
private android.widget.PopupWindow
mPopupKeyboard
private android.view.View
mMiniKeyboardContainer
private KeyboardView
mMiniKeyboard
private boolean
mMiniKeyboardOnScreen
private android.view.View
mPopupParent
private int
mMiniKeyboardOffsetX
private int
mMiniKeyboardOffsetY
private Map
mMiniKeyboardCache
private android.inputmethodservice.Keyboard.Key[]
mKeys
private OnKeyboardActionListener
mKeyboardActionListener
Listener for {@link OnKeyboardActionListener}.
private static final int
MSG_SHOW_PREVIEW
private static final int
MSG_REMOVE_PREVIEW
private static final int
MSG_REPEAT
private static final int
MSG_LONGPRESS
private static final int
DELAY_BEFORE_PREVIEW
private static final int
DELAY_AFTER_PREVIEW
private static final int
DEBOUNCE_TIME
private int
mVerticalCorrection
private int
mProximityThreshold
private boolean
mPreviewCentered
private boolean
mShowPreview
private boolean
mShowTouchPoints
private int
mPopupPreviewX
private int
mPopupPreviewY
private int
mLastX
private int
mLastY
private int
mStartX
private int
mStartY
private boolean
mProximityCorrectOn
private android.graphics.Paint
mPaint
private android.graphics.Rect
mPadding
private long
mDownTime
private long
mLastMoveTime
private int
mLastKey
private int
mLastCodeX
private int
mLastCodeY
private int
mCurrentKey
private int
mDownKey
private long
mLastKeyTime
private long
mCurrentKeyTime
private int[]
mKeyIndices
private android.view.GestureDetector
mGestureDetector
private int
mPopupX
private int
mPopupY
private int
mRepeatKeyIndex
private int
mPopupLayout
private boolean
mAbortKey
private android.inputmethodservice.Keyboard.Key
mInvalidatedKey
private android.graphics.Rect
mClipRegion
private boolean
mPossiblePoly
private SwipeTracker
mSwipeTracker
private int
mSwipeThreshold
private boolean
mDisambiguateSwipe
private int
mOldPointerCount
private float
mOldPointerX
private float
mOldPointerY
private android.graphics.drawable.Drawable
mKeyBackground
private static final int
REPEAT_INTERVAL
private static final int
REPEAT_START_DELAY
private static final int
LONGPRESS_TIMEOUT
private static int
MAX_NEARBY_KEYS
private int[]
mDistances
private int
mLastSentIndex
private int
mTapCount
private long
mLastTapTime
private boolean
mInMultiTap
private static final int
MULTITAP_INTERVAL
private StringBuilder
mPreviewLabel
private boolean
mDrawPending
Whether the keyboard bitmap needs to be redrawn before it's blitted.
private android.graphics.Rect
mDirtyRect
The dirty region in the keyboard bitmap
private android.graphics.Bitmap
mBuffer
The keyboard bitmap for faster updates
private boolean
mKeyboardChanged
Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer.
private android.graphics.Canvas
mCanvas
The canvas for the above mutable keyboard bitmap
private android.view.accessibility.AccessibilityManager
mAccessibilityManager
The accessibility manager for accessibility support
private android.media.AudioManager
mAudioManager
The audio manager for accessibility support
private boolean
mHeadsetRequiredToHearPasswordsAnnounced
Whether the requirement of a headset to hear passwords if accessibility is enabled is announced.
android.os.Handler
mHandler
Constructors Summary
public KeyboardView(android.content.Context context, android.util.AttributeSet attrs)


         
        this(context, attrs, com.android.internal.R.attr.keyboardViewStyle);
    
public KeyboardView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)

        this(context, attrs, defStyleAttr, 0);
    
public KeyboardView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)

        super(context, attrs, defStyleAttr, defStyleRes);

        TypedArray a = context.obtainStyledAttributes(
                attrs, android.R.styleable.KeyboardView, defStyleAttr, defStyleRes);

        LayoutInflater inflate =
                (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        int previewLayout = 0;
        int keyTextSize = 0;

        int n = a.getIndexCount();
        
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);

            switch (attr) {
            case com.android.internal.R.styleable.KeyboardView_keyBackground:
                mKeyBackground = a.getDrawable(attr);
                break;
            case com.android.internal.R.styleable.KeyboardView_verticalCorrection:
                mVerticalCorrection = a.getDimensionPixelOffset(attr, 0);
                break;
            case com.android.internal.R.styleable.KeyboardView_keyPreviewLayout:
                previewLayout = a.getResourceId(attr, 0);
                break;
            case com.android.internal.R.styleable.KeyboardView_keyPreviewOffset:
                mPreviewOffset = a.getDimensionPixelOffset(attr, 0);
                break;
            case com.android.internal.R.styleable.KeyboardView_keyPreviewHeight:
                mPreviewHeight = a.getDimensionPixelSize(attr, 80);
                break;
            case com.android.internal.R.styleable.KeyboardView_keyTextSize:
                mKeyTextSize = a.getDimensionPixelSize(attr, 18);
                break;
            case com.android.internal.R.styleable.KeyboardView_keyTextColor:
                mKeyTextColor = a.getColor(attr, 0xFF000000);
                break;
            case com.android.internal.R.styleable.KeyboardView_labelTextSize:
                mLabelTextSize = a.getDimensionPixelSize(attr, 14);
                break;
            case com.android.internal.R.styleable.KeyboardView_popupLayout:
                mPopupLayout = a.getResourceId(attr, 0);
                break;
            case com.android.internal.R.styleable.KeyboardView_shadowColor:
                mShadowColor = a.getColor(attr, 0);
                break;
            case com.android.internal.R.styleable.KeyboardView_shadowRadius:
                mShadowRadius = a.getFloat(attr, 0f);
                break;
            }
        }
        
        a = mContext.obtainStyledAttributes(
                com.android.internal.R.styleable.Theme);
        mBackgroundDimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);

        mPreviewPopup = new PopupWindow(context);
        if (previewLayout != 0) {
            mPreviewText = (TextView) inflate.inflate(previewLayout, null);
            mPreviewTextSizeLarge = (int) mPreviewText.getTextSize();
            mPreviewPopup.setContentView(mPreviewText);
            mPreviewPopup.setBackgroundDrawable(null);
        } else {
            mShowPreview = false;
        }
        
        mPreviewPopup.setTouchable(false);
        
        mPopupKeyboard = new PopupWindow(context);
        mPopupKeyboard.setBackgroundDrawable(null);
        //mPopupKeyboard.setClippingEnabled(false);
        
        mPopupParent = this;
        //mPredicting = true;
        
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(keyTextSize);
        mPaint.setTextAlign(Align.CENTER);
        mPaint.setAlpha(255);

        mPadding = new Rect(0, 0, 0, 0);
        mMiniKeyboardCache = new HashMap<Key,View>();
        mKeyBackground.getPadding(mPadding);

        mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density);
        mDisambiguateSwipe = getResources().getBoolean(
                com.android.internal.R.bool.config_swipeDisambiguation);

        mAccessibilityManager = AccessibilityManager.getInstance(context);
        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

        resetMultiTap();
        initGestureDetector();
    
Methods Summary
private java.lang.CharSequenceadjustCase(java.lang.CharSequence label)

        if (mKeyboard.isShifted() && label != null && label.length() < 3
                && Character.isLowerCase(label.charAt(0))) {
            label = label.toString().toUpperCase();
        }
        return label;
    
private voidcheckMultiTap(long eventTime, int keyIndex)

        if (keyIndex == NOT_A_KEY) return;
        Key key = mKeys[keyIndex];
        if (key.codes.length > 1) {
            mInMultiTap = true;
            if (eventTime < mLastTapTime + MULTITAP_INTERVAL
                    && keyIndex == mLastSentIndex) {
                mTapCount = (mTapCount + 1) % key.codes.length;
                return;
            } else {
                mTapCount = -1;
                return;
            }
        }
        if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) {
            resetMultiTap();
        }
    
public voidclosing()

        if (mPreviewPopup.isShowing()) {
            mPreviewPopup.dismiss();
        }
        removeMessages();
        
        dismissPopupKeyboard();
        mBuffer = null;
        mCanvas = null;
        mMiniKeyboardCache.clear();
    
private voidcomputeProximityThreshold(Keyboard keyboard)
Compute the average distance between adjacent keys (horizontally and vertically) and square it to get the proximity threshold. We use a square here and in computing the touch distance from a key's center to avoid taking a square root.

param
keyboard

        if (keyboard == null) return;
        final Key[] keys = mKeys;
        if (keys == null) return;
        int length = keys.length;
        int dimensionSum = 0;
        for (int i = 0; i < length; i++) {
            Key key = keys[i];
            dimensionSum += Math.min(key.width, key.height) + key.gap;
        }
        if (dimensionSum < 0 || length == 0) return;
        mProximityThreshold = (int) (dimensionSum * 1.4f / length);
        mProximityThreshold *= mProximityThreshold; // Square it
    
private voiddetectAndSendKey(int index, int x, int y, long eventTime)

        if (index != NOT_A_KEY && index < mKeys.length) {
            final Key key = mKeys[index];
            if (key.text != null) {
                mKeyboardActionListener.onText(key.text);
                mKeyboardActionListener.onRelease(NOT_A_KEY);
            } else {
                int code = key.codes[0];
                //TextEntryState.keyPressedAt(key, x, y);
                int[] codes = new int[MAX_NEARBY_KEYS];
                Arrays.fill(codes, NOT_A_KEY);
                getKeyIndices(x, y, codes);
                // Multi-tap
                if (mInMultiTap) {
                    if (mTapCount != -1) {
                        mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE);
                    } else {
                        mTapCount = 0;
                    }
                    code = key.codes[mTapCount];
                }
                mKeyboardActionListener.onKey(code, codes);
                mKeyboardActionListener.onRelease(code);
            }
            mLastSentIndex = index;
            mLastTapTime = eventTime;
        }
    
private voiddismissPopupKeyboard()

        if (mPopupKeyboard.isShowing()) {
            mPopupKeyboard.dismiss();
            mMiniKeyboardOnScreen = false;
            invalidateAllKeys();
        }
    
private intgetKeyIndices(int x, int y, int[] allKeys)

        final Key[] keys = mKeys;
        int primaryIndex = NOT_A_KEY;
        int closestKey = NOT_A_KEY;
        int closestKeyDist = mProximityThreshold + 1;
        java.util.Arrays.fill(mDistances, Integer.MAX_VALUE);
        int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y);
        final int keyCount = nearestKeyIndices.length;
        for (int i = 0; i < keyCount; i++) {
            final Key key = keys[nearestKeyIndices[i]];
            int dist = 0;
            boolean isInside = key.isInside(x,y);
            if (isInside) {
                primaryIndex = nearestKeyIndices[i];
            }

            if (((mProximityCorrectOn 
                    && (dist = key.squaredDistanceFrom(x, y)) < mProximityThreshold) 
                    || isInside)
                    && key.codes[0] > 32) {
                // Find insertion point
                final int nCodes = key.codes.length;
                if (dist < closestKeyDist) {
                    closestKeyDist = dist;
                    closestKey = nearestKeyIndices[i];
                }
                
                if (allKeys == null) continue;
                
                for (int j = 0; j < mDistances.length; j++) {
                    if (mDistances[j] > dist) {
                        // Make space for nCodes codes
                        System.arraycopy(mDistances, j, mDistances, j + nCodes,
                                mDistances.length - j - nCodes);
                        System.arraycopy(allKeys, j, allKeys, j + nCodes,
                                allKeys.length - j - nCodes);
                        for (int c = 0; c < nCodes; c++) {
                            allKeys[j + c] = key.codes[c];
                            mDistances[j + c] = dist;
                        }
                        break;
                    }
                }
            }
        }
        if (primaryIndex == NOT_A_KEY) {
            primaryIndex = closestKey;
        }
        return primaryIndex;
    
public KeyboardgetKeyboard()
Returns the current keyboard being displayed by this view.

return
the currently attached keyboard
see
#setKeyboard(Keyboard)

        return mKeyboard;
    
protected android.inputmethodservice.KeyboardView$OnKeyboardActionListenergetOnKeyboardActionListener()
Returns the {@link OnKeyboardActionListener} object.

return
the listener attached to this keyboard

        return mKeyboardActionListener;
    
private java.lang.CharSequencegetPreviewText(android.inputmethodservice.Keyboard.Key key)
Handle multi-tap keys by producing the key label for the current multi-tap state.

        if (mInMultiTap) {
            // Multi-tap
            mPreviewLabel.setLength(0);
            mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]);
            return adjustCase(mPreviewLabel);
        } else {
            return adjustCase(key.label);
        }
    
public booleanhandleBack()

        if (mPopupKeyboard.isShowing()) {
            dismissPopupKeyboard();
            return true;
        }
        return false;
    
private voidinitGestureDetector()

        mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onFling(MotionEvent me1, MotionEvent me2, 
                    float velocityX, float velocityY) {
                if (mPossiblePoly) return false;
                final float absX = Math.abs(velocityX);
                final float absY = Math.abs(velocityY);
                float deltaX = me2.getX() - me1.getX();
                float deltaY = me2.getY() - me1.getY();
                int travelX = getWidth() / 2; // Half the keyboard width
                int travelY = getHeight() / 2; // Half the keyboard height
                mSwipeTracker.computeCurrentVelocity(1000);
                final float endingVelocityX = mSwipeTracker.getXVelocity();
                final float endingVelocityY = mSwipeTracker.getYVelocity();
                boolean sendDownKey = false;
                if (velocityX > mSwipeThreshold && absY < absX && deltaX > travelX) {
                    if (mDisambiguateSwipe && endingVelocityX < velocityX / 4) {
                        sendDownKey = true;
                    } else {
                        swipeRight();
                        return true;
                    }
                } else if (velocityX < -mSwipeThreshold && absY < absX && deltaX < -travelX) {
                    if (mDisambiguateSwipe && endingVelocityX > velocityX / 4) {
                        sendDownKey = true;
                    } else {
                        swipeLeft();
                        return true;
                    }
                } else if (velocityY < -mSwipeThreshold && absX < absY && deltaY < -travelY) {
                    if (mDisambiguateSwipe && endingVelocityY > velocityY / 4) {
                        sendDownKey = true;
                    } else {
                        swipeUp();
                        return true;
                    }
                } else if (velocityY > mSwipeThreshold && absX < absY / 2 && deltaY > travelY) {
                    if (mDisambiguateSwipe && endingVelocityY < velocityY / 4) {
                        sendDownKey = true;
                    } else {
                        swipeDown();
                        return true;
                    }
                }

                if (sendDownKey) {
                    detectAndSendKey(mDownKey, mStartX, mStartY, me1.getEventTime());
                }
                return false;
            }
        });

        mGestureDetector.setIsLongpressEnabled(false);
    
public voidinvalidateAllKeys()
Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient because the keyboard renders the keys to an off-screen buffer and an invalidate() only draws the cached buffer.

see
#invalidateKey(int)

        mDirtyRect.union(0, 0, getWidth(), getHeight());
        mDrawPending = true;
        invalidate();
    
public voidinvalidateKey(int keyIndex)
Invalidates a key so that it will be redrawn on the next repaint. Use this method if only one key is changing it's content. Any changes that affect the position or size of the key may not be honored.

param
keyIndex the index of the key in the attached {@link Keyboard}.
see
#invalidateAllKeys

        if (mKeys == null) return;
        if (keyIndex < 0 || keyIndex >= mKeys.length) {
            return;
        }
        final Key key = mKeys[keyIndex];
        mInvalidatedKey = key;
        mDirtyRect.union(key.x + mPaddingLeft, key.y + mPaddingTop, 
                key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
        onBufferDraw();
        invalidate(key.x + mPaddingLeft, key.y + mPaddingTop, 
                key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
    
public booleanisPreviewEnabled()
Returns the enabled state of the key feedback popup.

return
whether or not the key feedback popup is enabled
see
#setPreviewEnabled(boolean)

        return mShowPreview;
    
public booleanisProximityCorrectionEnabled()
Returns true if proximity correction is enabled.

        return mProximityCorrectOn;
    
public booleanisShifted()
Returns the state of the shift key of the keyboard, if any.

return
true if the shift is in a pressed state, false otherwise. If there is no shift key on the keyboard or there is no keyboard attached, it returns false.
see
KeyboardView#setShifted(boolean)

        if (mKeyboard != null) {
            return mKeyboard.isShifted();
        }
        return false;
    
private voidonBufferDraw()

        if (mBuffer == null || mKeyboardChanged) {
            if (mBuffer == null || mKeyboardChanged &&
                    (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) {
                // Make sure our bitmap is at least 1x1
                final int width = Math.max(1, getWidth());
                final int height = Math.max(1, getHeight());
                mBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                mCanvas = new Canvas(mBuffer);
            }
            invalidateAllKeys();
            mKeyboardChanged = false;
        }
        final Canvas canvas = mCanvas;
        canvas.clipRect(mDirtyRect, Op.REPLACE);
        
        if (mKeyboard == null) return;
        
        final Paint paint = mPaint;
        final Drawable keyBackground = mKeyBackground;
        final Rect clipRegion = mClipRegion;
        final Rect padding = mPadding;
        final int kbdPaddingLeft = mPaddingLeft;
        final int kbdPaddingTop = mPaddingTop;
        final Key[] keys = mKeys;
        final Key invalidKey = mInvalidatedKey;

        paint.setColor(mKeyTextColor);
        boolean drawSingleKey = false;
        if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
          // Is clipRegion completely contained within the invalidated key?
          if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left &&
                  invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top &&
                  invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right &&
                  invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) {
              drawSingleKey = true;
          }
        }
        canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
        final int keyCount = keys.length;
        for (int i = 0; i < keyCount; i++) {
            final Key key = keys[i];
            if (drawSingleKey && invalidKey != key) {
                continue;
            }
            int[] drawableState = key.getCurrentDrawableState();
            keyBackground.setState(drawableState);

            // Switch the character to uppercase if shift is pressed
            String label = key.label == null? null : adjustCase(key.label).toString();
            
            final Rect bounds = keyBackground.getBounds();
            if (key.width != bounds.right || 
                    key.height != bounds.bottom) {
                keyBackground.setBounds(0, 0, key.width, key.height);
            }
            canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop);
            keyBackground.draw(canvas);
            
            if (label != null) {
                // For characters, use large font. For labels like "Done", use small font.
                if (label.length() > 1 && key.codes.length < 2) {
                    paint.setTextSize(mLabelTextSize);
                    paint.setTypeface(Typeface.DEFAULT_BOLD);
                } else {
                    paint.setTextSize(mKeyTextSize);
                    paint.setTypeface(Typeface.DEFAULT);
                }
                // Draw a drop shadow for the text
                paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor);
                // Draw the text
                canvas.drawText(label,
                    (key.width - padding.left - padding.right) / 2
                            + padding.left,
                    (key.height - padding.top - padding.bottom) / 2
                            + (paint.getTextSize() - paint.descent()) / 2 + padding.top,
                    paint);
                // Turn off drop shadow
                paint.setShadowLayer(0, 0, 0, 0);
            } else if (key.icon != null) {
                final int drawableX = (key.width - padding.left - padding.right 
                                - key.icon.getIntrinsicWidth()) / 2 + padding.left;
                final int drawableY = (key.height - padding.top - padding.bottom 
                        - key.icon.getIntrinsicHeight()) / 2 + padding.top;
                canvas.translate(drawableX, drawableY);
                key.icon.setBounds(0, 0, 
                        key.icon.getIntrinsicWidth(), key.icon.getIntrinsicHeight());
                key.icon.draw(canvas);
                canvas.translate(-drawableX, -drawableY);
            }
            canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop);
        }
        mInvalidatedKey = null;
        // Overlay a dark rectangle to dim the keyboard
        if (mMiniKeyboardOnScreen) {
            paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24);
            canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
        }

        if (DEBUG && mShowTouchPoints) {
            paint.setAlpha(128);
            paint.setColor(0xFFFF0000);
            canvas.drawCircle(mStartX, mStartY, 3, paint);
            canvas.drawLine(mStartX, mStartY, mLastX, mLastY, paint);
            paint.setColor(0xFF0000FF);
            canvas.drawCircle(mLastX, mLastY, 3, paint);
            paint.setColor(0xFF00FF00);
            canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint);
        }
        
        mDrawPending = false;
        mDirtyRect.setEmpty();
    
public voidonClick(android.view.View v)
Popup keyboard close button clicked.

hide

        dismissPopupKeyboard();
    
public voidonDetachedFromWindow()

        super.onDetachedFromWindow();
        closing();
    
public voidonDraw(android.graphics.Canvas canvas)

        super.onDraw(canvas);
        if (mDrawPending || mBuffer == null || mKeyboardChanged) {
            onBufferDraw();
        }
        canvas.drawBitmap(mBuffer, 0, 0, null);
    
public booleanonHoverEvent(android.view.MotionEvent event)

        if (mAccessibilityManager.isTouchExplorationEnabled() && event.getPointerCount() == 1) {
            final int action = event.getAction();
            switch (action) {
                case MotionEvent.ACTION_HOVER_ENTER: {
                    event.setAction(MotionEvent.ACTION_DOWN);
                } break;
                case MotionEvent.ACTION_HOVER_MOVE: {
                    event.setAction(MotionEvent.ACTION_MOVE);
                } break;
                case MotionEvent.ACTION_HOVER_EXIT: {
                    event.setAction(MotionEvent.ACTION_UP);
                } break;
            }
            return onTouchEvent(event);
        }
        return true;
    
protected booleanonLongPress(android.inputmethodservice.Keyboard.Key popupKey)
Called when a key is long pressed. By default this will open any popup keyboard associated with this key through the attributes popupLayout and popupCharacters.

param
popupKey the key that was long pressed
return
true if the long press is handled, false otherwise. Subclasses should call the method on the base class if the subclass doesn't wish to handle the call.

        int popupKeyboardId = popupKey.popupResId;

        if (popupKeyboardId != 0) {
            mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey);
            if (mMiniKeyboardContainer == null) {
                LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                        Context.LAYOUT_INFLATER_SERVICE);
                mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null);
                mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById(
                        com.android.internal.R.id.keyboardView);
                View closeButton = mMiniKeyboardContainer.findViewById(
                        com.android.internal.R.id.closeButton);
                if (closeButton != null) closeButton.setOnClickListener(this);
                mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() {
                    public void onKey(int primaryCode, int[] keyCodes) {
                        mKeyboardActionListener.onKey(primaryCode, keyCodes);
                        dismissPopupKeyboard();
                    }
                    
                    public void onText(CharSequence text) {
                        mKeyboardActionListener.onText(text);
                        dismissPopupKeyboard();
                    }
                    
                    public void swipeLeft() { }
                    public void swipeRight() { }
                    public void swipeUp() { }
                    public void swipeDown() { }
                    public void onPress(int primaryCode) {
                        mKeyboardActionListener.onPress(primaryCode);
                    }
                    public void onRelease(int primaryCode) {
                        mKeyboardActionListener.onRelease(primaryCode);
                    }
                });
                //mInputView.setSuggest(mSuggest);
                Keyboard keyboard;
                if (popupKey.popupCharacters != null) {
                    keyboard = new Keyboard(getContext(), popupKeyboardId, 
                            popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight());
                } else {
                    keyboard = new Keyboard(getContext(), popupKeyboardId);
                }
                mMiniKeyboard.setKeyboard(keyboard);
                mMiniKeyboard.setPopupParent(this);
                mMiniKeyboardContainer.measure(
                        MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), 
                        MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
                
                mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer);
            } else {
                mMiniKeyboard = (KeyboardView) mMiniKeyboardContainer.findViewById(
                        com.android.internal.R.id.keyboardView);
            }
            getLocationInWindow(mCoordinates);
            mPopupX = popupKey.x + mPaddingLeft;
            mPopupY = popupKey.y + mPaddingTop;
            mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth();
            mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight();
            final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mCoordinates[0];
            final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mCoordinates[1];
            mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y);
            mMiniKeyboard.setShifted(isShifted());
            mPopupKeyboard.setContentView(mMiniKeyboardContainer);
            mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth());
            mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight());
            mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
            mMiniKeyboardOnScreen = true;
            //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me));
            invalidateAllKeys();
            return true;
        }
        return false;
    
public voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

        // Round up a little
        if (mKeyboard == null) {
            setMeasuredDimension(mPaddingLeft + mPaddingRight, mPaddingTop + mPaddingBottom);
        } else {
            int width = mKeyboard.getMinWidth() + mPaddingLeft + mPaddingRight;
            if (MeasureSpec.getSize(widthMeasureSpec) < width + 10) {
                width = MeasureSpec.getSize(widthMeasureSpec);
            }
            setMeasuredDimension(width, mKeyboard.getHeight() + mPaddingTop + mPaddingBottom);
        }
    
private booleanonModifiedTouchEvent(android.view.MotionEvent me, boolean possiblePoly)

        int touchX = (int) me.getX() - mPaddingLeft;
        int touchY = (int) me.getY() - mPaddingTop;
        if (touchY >= -mVerticalCorrection)
            touchY += mVerticalCorrection;
        final int action = me.getAction();
        final long eventTime = me.getEventTime();
        int keyIndex = getKeyIndices(touchX, touchY, null);
        mPossiblePoly = possiblePoly;

        // Track the last few movements to look for spurious swipes.
        if (action == MotionEvent.ACTION_DOWN) mSwipeTracker.clear();
        mSwipeTracker.addMovement(me);

        // Ignore all motion events until a DOWN.
        if (mAbortKey
                && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) {
            return true;
        }

        if (mGestureDetector.onTouchEvent(me)) {
            showPreview(NOT_A_KEY);
            mHandler.removeMessages(MSG_REPEAT);
            mHandler.removeMessages(MSG_LONGPRESS);
            return true;
        }
        
        // Needs to be called after the gesture detector gets a turn, as it may have
        // displayed the mini keyboard
        if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) {
            return true;
        }

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mAbortKey = false;
                mStartX = touchX;
                mStartY = touchY;
                mLastCodeX = touchX;
                mLastCodeY = touchY;
                mLastKeyTime = 0;
                mCurrentKeyTime = 0;
                mLastKey = NOT_A_KEY;
                mCurrentKey = keyIndex;
                mDownKey = keyIndex;
                mDownTime = me.getEventTime();
                mLastMoveTime = mDownTime;
                checkMultiTap(eventTime, keyIndex);
                mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ? 
                        mKeys[keyIndex].codes[0] : 0);
                if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) {
                    mRepeatKeyIndex = mCurrentKey;
                    Message msg = mHandler.obtainMessage(MSG_REPEAT);
                    mHandler.sendMessageDelayed(msg, REPEAT_START_DELAY);
                    repeatKey();
                    // Delivering the key could have caused an abort
                    if (mAbortKey) {
                        mRepeatKeyIndex = NOT_A_KEY;
                        break;
                    }
                }
                if (mCurrentKey != NOT_A_KEY) {
                    Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me);
                    mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT);
                }
                showPreview(keyIndex);
                break;

            case MotionEvent.ACTION_MOVE:
                boolean continueLongPress = false;
                if (keyIndex != NOT_A_KEY) {
                    if (mCurrentKey == NOT_A_KEY) {
                        mCurrentKey = keyIndex;
                        mCurrentKeyTime = eventTime - mDownTime;
                    } else {
                        if (keyIndex == mCurrentKey) {
                            mCurrentKeyTime += eventTime - mLastMoveTime;
                            continueLongPress = true;
                        } else if (mRepeatKeyIndex == NOT_A_KEY) {
                            resetMultiTap();
                            mLastKey = mCurrentKey;
                            mLastCodeX = mLastX;
                            mLastCodeY = mLastY;
                            mLastKeyTime =
                                    mCurrentKeyTime + eventTime - mLastMoveTime;
                            mCurrentKey = keyIndex;
                            mCurrentKeyTime = 0;
                        }
                    }
                }
                if (!continueLongPress) {
                    // Cancel old longpress
                    mHandler.removeMessages(MSG_LONGPRESS);
                    // Start new longpress if key has changed
                    if (keyIndex != NOT_A_KEY) {
                        Message msg = mHandler.obtainMessage(MSG_LONGPRESS, me);
                        mHandler.sendMessageDelayed(msg, LONGPRESS_TIMEOUT);
                    }
                }
                showPreview(mCurrentKey);
                mLastMoveTime = eventTime;
                break;

            case MotionEvent.ACTION_UP:
                removeMessages();
                if (keyIndex == mCurrentKey) {
                    mCurrentKeyTime += eventTime - mLastMoveTime;
                } else {
                    resetMultiTap();
                    mLastKey = mCurrentKey;
                    mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime;
                    mCurrentKey = keyIndex;
                    mCurrentKeyTime = 0;
                }
                if (mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < DEBOUNCE_TIME
                        && mLastKey != NOT_A_KEY) {
                    mCurrentKey = mLastKey;
                    touchX = mLastCodeX;
                    touchY = mLastCodeY;
                }
                showPreview(NOT_A_KEY);
                Arrays.fill(mKeyIndices, NOT_A_KEY);
                // If we're not on a repeating key (which sends on a DOWN event)
                if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) {
                    detectAndSendKey(mCurrentKey, touchX, touchY, eventTime);
                }
                invalidateKey(keyIndex);
                mRepeatKeyIndex = NOT_A_KEY;
                break;
            case MotionEvent.ACTION_CANCEL:
                removeMessages();
                dismissPopupKeyboard();
                mAbortKey = true;
                showPreview(NOT_A_KEY);
                invalidateKey(mCurrentKey);
                break;
        }
        mLastX = touchX;
        mLastY = touchY;
        return true;
    
public voidonSizeChanged(int w, int h, int oldw, int oldh)

        super.onSizeChanged(w, h, oldw, oldh);
        if (mKeyboard != null) {
            mKeyboard.resize(w, h);
        }
        // Release the buffer, if any and it will be reallocated on the next draw
        mBuffer = null;
    
public booleanonTouchEvent(android.view.MotionEvent me)

        // Convert multi-pointer up/down events to single up/down events to 
        // deal with the typical multi-pointer behavior of two-thumb typing
        final int pointerCount = me.getPointerCount();
        final int action = me.getAction();
        boolean result = false;
        final long now = me.getEventTime();

        if (pointerCount != mOldPointerCount) {
            if (pointerCount == 1) {
                // Send a down event for the latest pointer
                MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
                        me.getX(), me.getY(), me.getMetaState());
                result = onModifiedTouchEvent(down, false);
                down.recycle();
                // If it's an up action, then deliver the up as well.
                if (action == MotionEvent.ACTION_UP) {
                    result = onModifiedTouchEvent(me, true);
                }
            } else {
                // Send an up event for the last pointer
                MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP,
                        mOldPointerX, mOldPointerY, me.getMetaState());
                result = onModifiedTouchEvent(up, true);
                up.recycle();
            }
        } else {
            if (pointerCount == 1) {
                result = onModifiedTouchEvent(me, false);
                mOldPointerX = me.getX();
                mOldPointerY = me.getY();
            } else {
                // Don't do anything when 2 pointers are down and moving.
                result = true;
            }
        }
        mOldPointerCount = pointerCount;

        return result;
    
private booleanopenPopupIfRequired(android.view.MotionEvent me)

        // Check if we have a popup layout specified first.
        if (mPopupLayout == 0) {
            return false;
        }
        if (mCurrentKey < 0 || mCurrentKey >= mKeys.length) {
            return false;
        }

        Key popupKey = mKeys[mCurrentKey];        
        boolean result = onLongPress(popupKey);
        if (result) {
            mAbortKey = true;
            showPreview(NOT_A_KEY);
        }
        return result;
    
private voidremoveMessages()

        mHandler.removeMessages(MSG_REPEAT);
        mHandler.removeMessages(MSG_LONGPRESS);
        mHandler.removeMessages(MSG_SHOW_PREVIEW);
    
private booleanrepeatKey()

        Key key = mKeys[mRepeatKeyIndex];
        detectAndSendKey(mCurrentKey, key.x, key.y, mLastTapTime);
        return true;
    
private voidresetMultiTap()

        mLastSentIndex = NOT_A_KEY;
        mTapCount = 0;
        mLastTapTime = -1;
        mInMultiTap = false;
    
private voidsendAccessibilityEventForUnicodeCharacter(int eventType, int code)

        if (mAccessibilityManager.isEnabled()) {
            AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
            onInitializeAccessibilityEvent(event);
            String text = null;
            // This is very efficient since the properties are cached.
            final boolean speakPassword = Settings.Secure.getIntForUser(
                    mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0,
                    UserHandle.USER_CURRENT_OR_SELF) != 0;
            // Add text only if password announcement is enabled or if headset is
            // used to avoid leaking passwords.
            if (speakPassword || mAudioManager.isBluetoothA2dpOn()
                    || mAudioManager.isWiredHeadsetOn()) {
                switch (code) {
                    case Keyboard.KEYCODE_ALT:
                        text = mContext.getString(R.string.keyboardview_keycode_alt);
                        break;
                    case Keyboard.KEYCODE_CANCEL:
                        text = mContext.getString(R.string.keyboardview_keycode_cancel);
                        break;
                    case Keyboard.KEYCODE_DELETE:
                        text = mContext.getString(R.string.keyboardview_keycode_delete);
                        break;
                    case Keyboard.KEYCODE_DONE:
                        text = mContext.getString(R.string.keyboardview_keycode_done);
                        break;
                    case Keyboard.KEYCODE_MODE_CHANGE:
                        text = mContext.getString(R.string.keyboardview_keycode_mode_change);
                        break;
                    case Keyboard.KEYCODE_SHIFT:
                        text = mContext.getString(R.string.keyboardview_keycode_shift);
                        break;
                    case '\n":
                        text = mContext.getString(R.string.keyboardview_keycode_enter);
                        break;
                    default:
                        text = String.valueOf((char) code);
                }
            } else if (!mHeadsetRequiredToHearPasswordsAnnounced) {
                // We want the waring for required head set to be send with both the
                // hover enter and hover exit event, so set the flag after the exit.
                if (eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
                    mHeadsetRequiredToHearPasswordsAnnounced = true;
                }
                text = mContext.getString(R.string.keyboard_headset_required_to_hear_password);
            } else {
                text = mContext.getString(R.string.keyboard_password_character_no_headset);
            }
            event.getText().add(text);
            mAccessibilityManager.sendAccessibilityEvent(event);
        }
    
public voidsetKeyboard(Keyboard keyboard)
Attaches a keyboard to this view. The keyboard can be switched at any time and the view will re-layout itself to accommodate the keyboard.

see
Keyboard
see
#getKeyboard()
param
keyboard the keyboard to display in this view

        if (mKeyboard != null) {
            showPreview(NOT_A_KEY);
        }
        // Remove any pending messages
        removeMessages();
        mKeyboard = keyboard;
        List<Key> keys = mKeyboard.getKeys();
        mKeys = keys.toArray(new Key[keys.size()]);
        requestLayout();
        // Hint to reallocate the buffer if the size changed
        mKeyboardChanged = true;
        invalidateAllKeys();
        computeProximityThreshold(keyboard);
        mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views
        // Switching to a different keyboard should abort any pending keys so that the key up
        // doesn't get delivered to the old or new keyboard
        mAbortKey = true; // Until the next ACTION_DOWN
    
public voidsetOnKeyboardActionListener(android.inputmethodservice.KeyboardView$OnKeyboardActionListener listener)

        mKeyboardActionListener = listener;
    
public voidsetPopupOffset(int x, int y)

        mMiniKeyboardOffsetX = x;
        mMiniKeyboardOffsetY = y;
        if (mPreviewPopup.isShowing()) {
            mPreviewPopup.dismiss();
        }
    
public voidsetPopupParent(android.view.View v)

        mPopupParent = v;
    
public voidsetPreviewEnabled(boolean previewEnabled)
Enables or disables the key feedback popup. This is a popup that shows a magnified version of the depressed key. By default the preview is enabled.

param
previewEnabled whether or not to enable the key feedback popup
see
#isPreviewEnabled()

        mShowPreview = previewEnabled;
    
public voidsetProximityCorrectionEnabled(boolean enabled)
When enabled, calls to {@link OnKeyboardActionListener#onKey} will include key codes for adjacent keys. When disabled, only the primary key code will be reported.

param
enabled whether or not the proximity correction is enabled

        mProximityCorrectOn = enabled;
    
public booleansetShifted(boolean shifted)
Sets the state of the shift key of the keyboard, if any.

param
shifted whether or not to enable the state of the shift key
return
true if the shift key state changed, false if there was no change
see
KeyboardView#isShifted()

        if (mKeyboard != null) {
            if (mKeyboard.setShifted(shifted)) {
                // The whole keyboard probably needs to be redrawn
                invalidateAllKeys();
                return true;
            }
        }
        return false;
    
public voidsetVerticalCorrection(int verticalOffset)

        
    
private voidshowKey(int keyIndex)

        final PopupWindow previewPopup = mPreviewPopup;
        final Key[] keys = mKeys;
        if (keyIndex < 0 || keyIndex >= mKeys.length) return;
        Key key = keys[keyIndex];
        if (key.icon != null) {
            mPreviewText.setCompoundDrawables(null, null, null, 
                    key.iconPreview != null ? key.iconPreview : key.icon);
            mPreviewText.setText(null);
        } else {
            mPreviewText.setCompoundDrawables(null, null, null, null);
            mPreviewText.setText(getPreviewText(key));
            if (key.label.length() > 1 && key.codes.length < 2) {
                mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize);
                mPreviewText.setTypeface(Typeface.DEFAULT_BOLD);
            } else {
                mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge);
                mPreviewText.setTypeface(Typeface.DEFAULT);
            }
        }
        mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width 
                + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight());
        final int popupHeight = mPreviewHeight;
        LayoutParams lp = mPreviewText.getLayoutParams();
        if (lp != null) {
            lp.width = popupWidth;
            lp.height = popupHeight;
        }
        if (!mPreviewCentered) {
            mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft;
            mPopupPreviewY = key.y - popupHeight + mPreviewOffset;
        } else {
            // TODO: Fix this if centering is brought back
            mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2;
            mPopupPreviewY = - mPreviewText.getMeasuredHeight();
        }
        mHandler.removeMessages(MSG_REMOVE_PREVIEW);
        getLocationInWindow(mCoordinates);
        mCoordinates[0] += mMiniKeyboardOffsetX; // Offset may be zero
        mCoordinates[1] += mMiniKeyboardOffsetY; // Offset may be zero

        // Set the preview background state
        mPreviewText.getBackground().setState(
                key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET);
        mPopupPreviewX += mCoordinates[0];
        mPopupPreviewY += mCoordinates[1];

        // If the popup cannot be shown above the key, put it on the side
        getLocationOnScreen(mCoordinates);
        if (mPopupPreviewY + mCoordinates[1] < 0) {
            // If the key you're pressing is on the left side of the keyboard, show the popup on
            // the right, offset by enough to see at least one key to the left/right.
            if (key.x + key.width <= getWidth() / 2) {
                mPopupPreviewX += (int) (key.width * 2.5);
            } else {
                mPopupPreviewX -= (int) (key.width * 2.5);
            }
            mPopupPreviewY += popupHeight;
        }

        if (previewPopup.isShowing()) {
            previewPopup.update(mPopupPreviewX, mPopupPreviewY,
                    popupWidth, popupHeight);
        } else {
            previewPopup.setWidth(popupWidth);
            previewPopup.setHeight(popupHeight);
            previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, 
                    mPopupPreviewX, mPopupPreviewY);
        }
        mPreviewText.setVisibility(VISIBLE);
    
private voidshowPreview(int keyIndex)

        int oldKeyIndex = mCurrentKeyIndex;
        final PopupWindow previewPopup = mPreviewPopup;
        
        mCurrentKeyIndex = keyIndex;
        // Release the old key and press the new key
        final Key[] keys = mKeys;
        if (oldKeyIndex != mCurrentKeyIndex) {
            if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) {
                Key oldKey = keys[oldKeyIndex];
                oldKey.onReleased(mCurrentKeyIndex == NOT_A_KEY);
                invalidateKey(oldKeyIndex);
                final int keyCode = oldKey.codes[0];
                sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT,
                        keyCode);
                // TODO: We need to implement AccessibilityNodeProvider for this view.
                sendAccessibilityEventForUnicodeCharacter(
                        AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, keyCode);
            }
            if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) {
                Key newKey = keys[mCurrentKeyIndex];
                newKey.onPressed();
                invalidateKey(mCurrentKeyIndex);
                final int keyCode = newKey.codes[0];
                sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
                        keyCode);
                // TODO: We need to implement AccessibilityNodeProvider for this view.
                sendAccessibilityEventForUnicodeCharacter(
                        AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, keyCode);
            }
        }
        // If key changed and preview is on ...
        if (oldKeyIndex != mCurrentKeyIndex && mShowPreview) {
            mHandler.removeMessages(MSG_SHOW_PREVIEW);
            if (previewPopup.isShowing()) {
                if (keyIndex == NOT_A_KEY) {
                    mHandler.sendMessageDelayed(mHandler
                            .obtainMessage(MSG_REMOVE_PREVIEW), 
                            DELAY_AFTER_PREVIEW);
                }
            }
            if (keyIndex != NOT_A_KEY) {
                if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) {
                    // Show right away, if it's already visible and finger is moving around
                    showKey(keyIndex);
                } else {
                    mHandler.sendMessageDelayed(
                            mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0), 
                            DELAY_BEFORE_PREVIEW);
                }
            }
        }
    
protected voidswipeDown()

        mKeyboardActionListener.swipeDown();
    
protected voidswipeLeft()

        mKeyboardActionListener.swipeLeft();
    
protected voidswipeRight()

        mKeyboardActionListener.swipeRight();
    
protected voidswipeUp()

        mKeyboardActionListener.swipeUp();