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.suggestions; 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 import com.android.inputmethod.latin.R; 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 final class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel { 44 private final int[] mCoordinates = new int[2]; 45 46 final KeyDetector mModalPanelKeyDetector; 47 private final KeyDetector mSlidingPanelKeyDetector; 48 49 private Controller mController; 50 KeyboardActionListener mListener; 51 private int mOriginX; 52 private int mOriginY; 53 54 static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter(); 55 56 final KeyboardActionListener mSuggestionsPaneListener = 57 new KeyboardActionListener.Adapter() { 58 @Override 59 public void onPressKey(int primaryCode) { 60 mListener.onPressKey(primaryCode); 61 } 62 63 @Override 64 public void onReleaseKey(int primaryCode, boolean withSliding) { 65 mListener.onReleaseKey(primaryCode, withSliding); 66 } 67 68 @Override 69 public void onCodeInput(int primaryCode, int x, int y) { 70 final int index = primaryCode - MoreSuggestions.SUGGESTION_CODE_BASE; 71 if (index >= 0 && index < SuggestionStripView.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 public void updateKeyboardGeometry(final int keyHeight) { 109 mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes); 110 } 111 112 @Override 113 public void setKeyboard(Keyboard keyboard) { 114 super.setKeyboard(keyboard); 115 mModalPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop()); 116 mSlidingPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), 117 -getPaddingTop() + mVerticalCorrection); 118 } 119 120 @Override 121 public KeyDetector getKeyDetector() { 122 return mSlidingPanelKeyDetector; 123 } 124 125 @Override 126 public KeyboardActionListener getKeyboardActionListener() { 127 return mSuggestionsPaneListener; 128 } 129 130 @Override 131 public DrawingProxy getDrawingProxy() { 132 return this; 133 } 134 135 @Override 136 public TimerProxy getTimerProxy() { 137 return EMPTY_TIMER_PROXY; 138 } 139 140 @Override 141 public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) { 142 // Suggestions pane needs no pop-up key preview displayed, so we pass always false with a 143 // delay of 0. The delay does not matter actually since the popup is not shown anyway. 144 super.setKeyPreviewPopupEnabled(false, 0); 145 } 146 147 @Override 148 public void showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, 149 PopupWindow window, KeyboardActionListener listener) { 150 mController = controller; 151 mListener = listener; 152 final View container = (View)getParent(); 153 final MoreSuggestions pane = (MoreSuggestions)getKeyboard(); 154 final int defaultCoordX = pane.mOccupiedWidth / 2; 155 // The coordinates of panel's left-top corner in parentView's coordinate system. 156 final int x = pointX - defaultCoordX - container.getPaddingLeft(); 157 final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom(); 158 159 window.setContentView(container); 160 window.setWidth(container.getMeasuredWidth()); 161 window.setHeight(container.getMeasuredHeight()); 162 parentView.getLocationInWindow(mCoordinates); 163 window.showAtLocation(parentView, Gravity.NO_GRAVITY, 164 x + mCoordinates[0], y + mCoordinates[1]); 165 166 mOriginX = x + container.getPaddingLeft(); 167 mOriginY = y + container.getPaddingTop(); 168 } 169 170 private boolean mIsDismissing; 171 172 @Override 173 public boolean dismissMoreKeysPanel() { 174 if (mIsDismissing || mController == null) return false; 175 mIsDismissing = true; 176 final boolean dismissed = mController.dismissMoreKeysPanel(); 177 mIsDismissing = false; 178 return dismissed; 179 } 180 181 @Override 182 public int translateX(int x) { 183 return x - mOriginX; 184 } 185 186 @Override 187 public int translateY(int y) { 188 return y - mOriginY; 189 } 190 191 private final KeyEventHandler mModalPanelKeyEventHandler = new KeyEventHandler() { 192 @Override 193 public KeyDetector getKeyDetector() { 194 return mModalPanelKeyDetector; 195 } 196 197 @Override 198 public KeyboardActionListener getKeyboardActionListener() { 199 return mSuggestionsPaneListener; 200 } 201 202 @Override 203 public DrawingProxy getDrawingProxy() { 204 return MoreSuggestionsView.this; 205 } 206 207 @Override 208 public TimerProxy getTimerProxy() { 209 return EMPTY_TIMER_PROXY; 210 } 211 }; 212 213 @Override 214 public boolean onTouchEvent(MotionEvent me) { 215 final int action = me.getAction(); 216 final long eventTime = me.getEventTime(); 217 final int index = me.getActionIndex(); 218 final int id = me.getPointerId(index); 219 final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 220 final int x = (int)me.getX(index); 221 final int y = (int)me.getY(index); 222 tracker.processMotionEvent(action, x, y, eventTime, mModalPanelKeyEventHandler); 223 return true; 224 } 225 } 226