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 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 < 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 showMoreKeysPanel(View parentView, Controller controller, int pointX, int pointY, 145 PopupWindow window, KeyboardActionListener listener) { 146 mController = controller; 147 mListener = listener; 148 final View container = (View)getParent(); 149 final MoreSuggestions pane = (MoreSuggestions)getKeyboard(); 150 final int defaultCoordX = pane.mOccupiedWidth / 2; 151 // The coordinates of panel's left-top corner in parentView's coordinate system. 152 final int x = pointX - defaultCoordX - container.getPaddingLeft(); 153 final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom(); 154 155 window.setContentView(container); 156 window.setWidth(container.getMeasuredWidth()); 157 window.setHeight(container.getMeasuredHeight()); 158 parentView.getLocationInWindow(mCoordinates); 159 window.showAtLocation(parentView, Gravity.NO_GRAVITY, 160 x + mCoordinates[0], y + mCoordinates[1]); 161 162 mOriginX = x + container.getPaddingLeft(); 163 mOriginY = y + container.getPaddingTop(); 164 } 165 166 private boolean mIsDismissing; 167 168 @Override 169 public boolean dismissMoreKeysPanel() { 170 if (mIsDismissing || mController == null) return false; 171 mIsDismissing = true; 172 final boolean dismissed = mController.dismissMoreKeysPanel(); 173 mIsDismissing = false; 174 return dismissed; 175 } 176 177 @Override 178 public int translateX(int x) { 179 return x - mOriginX; 180 } 181 182 @Override 183 public int translateY(int y) { 184 return y - mOriginY; 185 } 186 187 private final KeyEventHandler mModalPanelKeyEventHandler = new KeyEventHandler() { 188 @Override 189 public KeyDetector getKeyDetector() { 190 return mModalPanelKeyDetector; 191 } 192 193 @Override 194 public KeyboardActionListener getKeyboardActionListener() { 195 return mSuggestionsPaneListener; 196 } 197 198 @Override 199 public DrawingProxy getDrawingProxy() { 200 return MoreSuggestionsView.this; 201 } 202 203 @Override 204 public TimerProxy getTimerProxy() { 205 return EMPTY_TIMER_PROXY; 206 } 207 }; 208 209 @Override 210 public boolean onTouchEvent(MotionEvent me) { 211 final int action = me.getAction(); 212 final long eventTime = me.getEventTime(); 213 final int index = me.getActionIndex(); 214 final int id = me.getPointerId(index); 215 final PointerTracker tracker = PointerTracker.getPointerTracker(id, this); 216 final int x = (int)me.getX(index); 217 final int y = (int)me.getY(index); 218 tracker.processMotionEvent(action, x, y, eventTime, mModalPanelKeyEventHandler); 219 return true; 220 } 221 } 222