Home | History | Annotate | Download | only in keyboard
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.inputmethod.keyboard;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.util.AttributeSet;
     22 import android.view.MotionEvent;
     23 import android.view.View;
     24 
     25 import com.android.inputmethod.latin.Constants;
     26 import com.android.inputmethod.latin.CoordinateUtils;
     27 import com.android.inputmethod.latin.R;
     28 
     29 /**
     30  * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and
     31  * detecting key presses and touch movements.
     32  */
     33 public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
     34     private final int[] mCoordinates = CoordinateUtils.newInstance();
     35 
     36     protected final KeyDetector mKeyDetector;
     37     private Controller mController;
     38     protected KeyboardActionListener mListener;
     39     private int mOriginX;
     40     private int mOriginY;
     41     private Key mCurrentKey;
     42 
     43     private int mActivePointerId;
     44 
     45     public MoreKeysKeyboardView(final Context context, final AttributeSet attrs) {
     46         this(context, attrs, R.attr.moreKeysKeyboardViewStyle);
     47     }
     48 
     49     public MoreKeysKeyboardView(final Context context, final AttributeSet attrs,
     50             final int defStyle) {
     51         super(context, attrs, defStyle);
     52 
     53         final Resources res = context.getResources();
     54         mKeyDetector = new MoreKeysDetector(
     55                 res.getDimension(R.dimen.more_keys_keyboard_slide_allowance));
     56     }
     57 
     58     @Override
     59     protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
     60         final Keyboard keyboard = getKeyboard();
     61         if (keyboard != null) {
     62             final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight();
     63             final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom();
     64             setMeasuredDimension(width, height);
     65         } else {
     66             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     67         }
     68     }
     69 
     70     @Override
     71     public void setKeyboard(final Keyboard keyboard) {
     72         super.setKeyboard(keyboard);
     73         mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
     74                 -getPaddingTop() + getVerticalCorrection());
     75     }
     76 
     77     @Override
     78     public void showMoreKeysPanel(final View parentView, final Controller controller,
     79             final int pointX, final int pointY, final KeyboardActionListener listener) {
     80         mController = controller;
     81         mListener = listener;
     82         final View container = getContainerView();
     83         // The coordinates of panel's left-top corner in parentView's coordinate system.
     84         final int x = pointX - getDefaultCoordX() - container.getPaddingLeft();
     85         final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom();
     86 
     87         parentView.getLocationInWindow(mCoordinates);
     88         // Ensure the horizontal position of the panel does not extend past the screen edges.
     89         final int maxX = parentView.getMeasuredWidth() - container.getMeasuredWidth();
     90         final int panelX = Math.max(0, Math.min(maxX, x)) + CoordinateUtils.x(mCoordinates);
     91         final int panelY = y + CoordinateUtils.y(mCoordinates);
     92         container.setX(panelX);
     93         container.setY(panelY);
     94 
     95         mOriginX = x + container.getPaddingLeft();
     96         mOriginY = y + container.getPaddingTop();
     97         controller.onShowMoreKeysPanel(this);
     98     }
     99 
    100     /**
    101      * Returns the default x coordinate for showing this panel.
    102      */
    103     protected int getDefaultCoordX() {
    104         return ((MoreKeysKeyboard)getKeyboard()).getDefaultCoordX();
    105     }
    106 
    107     @Override
    108     public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime) {
    109         mActivePointerId = pointerId;
    110         onMoveKeyInternal(x, y, pointerId);
    111     }
    112 
    113     @Override
    114     public void onMoveEvent(int x, int y, final int pointerId, long eventTime) {
    115         if (mActivePointerId != pointerId) {
    116             return;
    117         }
    118         final boolean hasOldKey = (mCurrentKey != null);
    119         onMoveKeyInternal(x, y, pointerId);
    120         if (hasOldKey && mCurrentKey == null) {
    121             // If the pointer has moved too far away from any target then cancel the panel.
    122             mController.onCancelMoreKeysPanel();
    123         }
    124     }
    125 
    126     @Override
    127     public void onUpEvent(final int x, final int y, final int pointerId, final long eventTime) {
    128         if (mCurrentKey != null && mActivePointerId == pointerId) {
    129             updateReleaseKeyGraphics(mCurrentKey);
    130             onCodeInput(mCurrentKey.mCode, x, y);
    131             mCurrentKey = null;
    132         }
    133     }
    134 
    135     /**
    136      * Performs the specific action for this panel when the user presses a key on the panel.
    137      */
    138     protected void onCodeInput(final int code, final int x, final int y) {
    139         if (code == Constants.CODE_OUTPUT_TEXT) {
    140             mListener.onTextInput(mCurrentKey.getOutputText());
    141         } else if (code != Constants.CODE_UNSPECIFIED) {
    142             mListener.onCodeInput(code, x, y);
    143         }
    144     }
    145 
    146     private void onMoveKeyInternal(int x, int y, int pointerId) {
    147         if (mActivePointerId != pointerId) {
    148             // Ignore old pointers when newer pointer is active.
    149             return;
    150         }
    151         final Key oldKey = mCurrentKey;
    152         final Key newKey = mKeyDetector.detectHitKey(x, y);
    153         if (newKey != oldKey) {
    154             mCurrentKey = newKey;
    155             invalidateKey(mCurrentKey);
    156             if (oldKey != null) {
    157                 updateReleaseKeyGraphics(oldKey);
    158             }
    159             if (newKey != null) {
    160                 updatePressKeyGraphics(newKey);
    161             }
    162         }
    163     }
    164 
    165     private void updateReleaseKeyGraphics(final Key key) {
    166         key.onReleased();
    167         invalidateKey(key);
    168     }
    169 
    170     private void updatePressKeyGraphics(final Key key) {
    171         key.onPressed();
    172         invalidateKey(key);
    173     }
    174 
    175     @Override
    176     public boolean dismissMoreKeysPanel() {
    177         if (mController == null) return false;
    178         return mController.onDismissMoreKeysPanel();
    179     }
    180 
    181     @Override
    182     public int translateX(final int x) {
    183         return x - mOriginX;
    184     }
    185 
    186     @Override
    187     public int translateY(final int y) {
    188         return y - mOriginY;
    189     }
    190 
    191     @Override
    192     public boolean onTouchEvent(final MotionEvent me) {
    193         final int action = me.getActionMasked();
    194         final long eventTime = me.getEventTime();
    195         final int index = me.getActionIndex();
    196         final int x = (int)me.getX(index);
    197         final int y = (int)me.getY(index);
    198         final int pointerId = me.getPointerId(index);
    199         processMotionEvent(action, x, y, pointerId, eventTime);
    200         return true;
    201     }
    202 
    203     public void processMotionEvent(final int action, final int x, final int y,
    204             final int pointerId, final long eventTime) {
    205         switch (action) {
    206         case MotionEvent.ACTION_DOWN:
    207         case MotionEvent.ACTION_POINTER_DOWN:
    208             onDownEvent(x, y, pointerId, eventTime);
    209             break;
    210         case MotionEvent.ACTION_UP:
    211         case MotionEvent.ACTION_POINTER_UP:
    212             onUpEvent(x, y, pointerId, eventTime);
    213             break;
    214         case MotionEvent.ACTION_MOVE:
    215             onMoveEvent(x, y, pointerId, eventTime);
    216             break;
    217         }
    218     }
    219 
    220     @Override
    221     public View getContainerView() {
    222         return (View)getParent();
    223     }
    224 
    225     @Override
    226     public boolean isShowingInParent() {
    227         return (getContainerView().getParent() != null);
    228     }
    229 }
    230