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.R; 27 import com.android.inputmethod.latin.utils.CoordinateUtils; 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 = EMPTY_CONTROLLER; 38 protected KeyboardActionListener mListener; 39 private int mOriginX; 40 private int mOriginY; 41 private Key mCurrentKey; 42 43 private int mActivePointerId; 44 MoreKeysKeyboardView(final Context context, final AttributeSet attrs)45 public MoreKeysKeyboardView(final Context context, final AttributeSet attrs) { 46 this(context, attrs, R.attr.moreKeysKeyboardViewStyle); 47 } 48 MoreKeysKeyboardView(final Context context, final AttributeSet attrs, final int defStyle)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 onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)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 setKeyboard(final Keyboard keyboard)71 public void setKeyboard(final Keyboard keyboard) { 72 super.setKeyboard(keyboard); 73 mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), 74 -getPaddingTop() + getVerticalCorrection()); 75 } 76 77 @Override showMoreKeysPanel(final View parentView, final Controller controller, final int pointX, final int pointY, final KeyboardActionListener listener)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 */ getDefaultCoordX()103 protected int getDefaultCoordX() { 104 return ((MoreKeysKeyboard)getKeyboard()).getDefaultCoordX(); 105 } 106 107 @Override onDownEvent(final int x, final int y, final int pointerId, final long eventTime)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 onMoveEvent(int x, int y, final int pointerId, long eventTime)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(this); 123 } 124 } 125 126 @Override onUpEvent(final int x, final int y, final int pointerId, final long eventTime)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.getCode(), 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 */ onCodeInput(final int code, final int x, final int y)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 onMoveKeyInternal(int x, int y, int pointerId)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 updateReleaseKeyGraphics(final Key key)165 private void updateReleaseKeyGraphics(final Key key) { 166 key.onReleased(); 167 invalidateKey(key); 168 } 169 updatePressKeyGraphics(final Key key)170 private void updatePressKeyGraphics(final Key key) { 171 key.onPressed(); 172 invalidateKey(key); 173 } 174 175 @Override dismissMoreKeysPanel()176 public void dismissMoreKeysPanel() { 177 if (!isShowingInParent()) { 178 return; 179 } 180 mController.onDismissMoreKeysPanel(this); 181 } 182 183 @Override translateX(final int x)184 public int translateX(final int x) { 185 return x - mOriginX; 186 } 187 188 @Override translateY(final int y)189 public int translateY(final int y) { 190 return y - mOriginY; 191 } 192 193 @Override onTouchEvent(final MotionEvent me)194 public boolean onTouchEvent(final MotionEvent me) { 195 final int action = me.getActionMasked(); 196 final long eventTime = me.getEventTime(); 197 final int index = me.getActionIndex(); 198 final int x = (int)me.getX(index); 199 final int y = (int)me.getY(index); 200 final int pointerId = me.getPointerId(index); 201 switch (action) { 202 case MotionEvent.ACTION_DOWN: 203 case MotionEvent.ACTION_POINTER_DOWN: 204 onDownEvent(x, y, pointerId, eventTime); 205 break; 206 case MotionEvent.ACTION_UP: 207 case MotionEvent.ACTION_POINTER_UP: 208 onUpEvent(x, y, pointerId, eventTime); 209 break; 210 case MotionEvent.ACTION_MOVE: 211 onMoveEvent(x, y, pointerId, eventTime); 212 break; 213 } 214 return true; 215 } 216 217 @Override getContainerView()218 public View getContainerView() { 219 return (View)getParent(); 220 } 221 222 @Override isShowingInParent()223 public boolean isShowingInParent() { 224 return (getContainerView().getParent() != null); 225 } 226 } 227