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.latin; 18 19 import android.content.Context; 20 import android.content.res.Resources; 21 import android.util.AttributeSet; 22 import android.view.Gravity; 23 import android.view.MotionEvent; 24 import android.view.View; 25 import android.widget.PopupWindow; 26 27 import com.android.inputmethod.keyboard.KeyDetector; 28 import com.android.inputmethod.keyboard.Keyboard; 29 import com.android.inputmethod.keyboard.KeyboardActionListener; 30 import com.android.inputmethod.keyboard.KeyboardView; 31 import com.android.inputmethod.keyboard.MoreKeysDetector; 32 import com.android.inputmethod.keyboard.MoreKeysPanel; 33 import com.android.inputmethod.keyboard.PointerTracker; 34 import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy; 35 import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler; 36 import com.android.inputmethod.keyboard.PointerTracker.TimerProxy; 37 38 39 /** 40 * A view that renders a virtual {@link MoreSuggestions}. It handles rendering of keys and detecting 41 * key presses and touch movements. 42 */ 43 public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel { 44 private final int[] mCoordinates = new int[2]; 45 46 private final KeyDetector mModalPanelKeyDetector; 47 private final KeyDetector mSlidingPanelKeyDetector; 48 49 private Controller mController; 50 private KeyboardActionListener mListener; 51 private int mOriginX; 52 private int mOriginY; 53 54 private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter(); 55 56 private final KeyboardActionListener mSuggestionsPaneListener = 57 new KeyboardActionListener.Adapter() { 58 @Override 59 public void onPress(int primaryCode, boolean withSliding) { 60 mListener.onPress(primaryCode, withSliding); 61 } 62 63 @Override 64 public void onRelease(int primaryCode, boolean withSliding) { 65 mListener.onRelease(primaryCode, withSliding); 66 } 67 68 @Override 69 public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { 70 final int index = primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE; 71 if (index >= 0 && index < SuggestionsView.MAX_SUGGESTIONS) { 72 mListener.onCustomRequest(index); 73 } 74 } 75 76 @Override 77 public void onCancelInput() { 78 mListener.onCancelInput(); 79 } 80 }; 81 82 public MoreSuggestionsView(Context context, AttributeSet attrs) { 83 this(context, attrs, R.attr.moreSuggestionsViewStyle); 84 } 85 86 public MoreSuggestionsView(Context context, AttributeSet attrs, int defStyle) { 87 super(context, attrs, defStyle); 88 89 final Resources res = context.getResources(); 90 mModalPanelKeyDetector = new KeyDetector(/* keyHysteresisDistance */ 0); 91 mSlidingPanelKeyDetector = new MoreKeysDetector( 92 res.getDimension(R.dimen.more_suggestions_slide_allowance)); 93 setKeyPreviewPopupEnabled(false, 0); 94 } 95 96 @Override 97 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 98 final Keyboard keyboard = getKeyboard(); 99 if (keyboard != null) { 100 final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); 101 final int height = keyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom(); 102 setMeasuredDimension(width, height); 103 } else { 104 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 105 } 106 } 107 108 @Override 109 public void setKeyboard(Keyboard keyboard) { 110 super.setKeyboard(keyboard); 111 mModalPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop()); 112 mSlidingPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), 113 -getPaddingTop() + mVerticalCorrection); 114 } 115 116 @Override 117 public KeyDetector getKeyDetector() { 118 return mSlidingPanelKeyDetector; 119 } 120 121 @Override 122 public KeyboardActionListener getKeyboardActionListener() { 123 return mSuggestionsPaneListener; 124 } 125 126 @Override 127 public DrawingProxy getDrawingProxy() { 128 return this; 129 } 130 131 @Override 132 public TimerProxy getTimerProxy() { 133 return EMPTY_TIMER_PROXY; 134 } 135 136 @Override 137 public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { 138 // Suggestions pane needs no pop-up key preview displayed, so we pass always false with a 139 // delay of 0. The delay does not matter actually since the popup is not shown anyway. 140 super.setKeyPreviewPopupEnabled(false, 0); 141 } 142 143 @Override 144 public void setShifted(boolean shifted) { 145 // Nothing to do with. 146 } 147 148 @Override 149 public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, 150 PopupWindow window, KeyboardActionListener listener) { 151 mController = controller; 152 mListener = listener; 153 final View container = (View)getParent(); 154 final MoreSuggestions pane = (MoreSuggestions)getKeyboard(); 155 156 parentView.getLocationInWindow(mCoordinates); 157 final int paneLeft = pointX - (pane.mOccupiedWidth / 2) + parentView.getPaddingLeft(); 158 final int x = wrapUp(Math.max(0, Math.min(paneLeft, 159 parentView.getWidth() - pane.mOccupiedWidth)) 160 - container.getPaddingLeft() + mCoordinates[0], 161 container.getMeasuredWidth(), 0, parentView.getWidth()); 162 final int y = pointY 163 - (container.getMeasuredHeight() - container.getPaddingBottom()) 164 + parentView.getPaddingTop() + mCoordinates[1]; 165 166 window.setContentView(container); 167 window.setWidth(container.getMeasuredWidth()); 168 window.setHeight(container.getMeasuredHeight()); 169 window.showAtLocation(parentView, Gravity.NO_GRAVITY, x, y); 170 171 mOriginX = x + container.getPaddingLeft() - mCoordinates[0]; 172 mOriginY = y + container.getPaddingTop() - mCoordinates[1]; 173 } 174 175 private static int wrapUp(int x, int width, int left, int right) { 176 if (x < left) 177 return left; 178 if (x + width > right) 179 return right - width; 180 return x; 181 } 182 183 @Override 184 public boolean dismissMoreKeysPanel() { 185 if (mController == null) return false; 186 return mController.dismissMoreKeysPanel(); 187 } 188 189 @Override 190 public int translateX(int x) { 191 return x - mOriginX; 192 } 193 194 @Override 195 public int translateY(int y) { 196 return y - mOriginY; 197 } 198 199 private final KeyEventHandler mModalPanelKeyEventHandler = new KeyEventHandler() { 200 @Override 201 public KeyDetector getKeyDetector() { 202 return mModalPanelKeyDetector; 203 } 204 205 @Override 206 public KeyboardActionListener getKeyboardActionListener() { 207 return mSuggestionsPaneListener; 208 } 209 210 @Override 211 public DrawingProxy getDrawingProxy() { 212 return MoreSuggestionsView.this; 213 } 214 215 @Override 216 public TimerProxy getTimerProxy() { 217 return EMPTY_TIMER_PROXY; 218 } 219 }; 220 221 @Override 222 public boolean onTouchEvent(MotionEvent me) { 223 final int action = me.getAction(); 224 final long eventTime = me.getEventTime(); 225 final int index = me.getActionIndex(); 226 final int id = me.getPointerId(index); 227 final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 228 final int x = (int)me.getX(index); 229 final int y = (int)me.getY(index); 230 tracker.processMotionEvent(action, x, y, eventTime, mModalPanelKeyEventHandler); 231 return true; 232 } 233 } 234