You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
601 lines
22 KiB
601 lines
22 KiB
/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License
|
|
*/
|
|
|
|
package com.android.inputmethod.leanback;
|
|
|
|
import android.graphics.PointF;
|
|
import android.inputmethodservice.InputMethodService;
|
|
import android.inputmethodservice.Keyboard;
|
|
import android.inputmethodservice.Keyboard.Key;
|
|
import android.util.Log;
|
|
import android.view.KeyEvent;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.inputmethod.EditorInfo;
|
|
|
|
import com.android.inputmethod.leanback.LeanbackKeyboardContainer.KeyFocus;
|
|
|
|
import java.util.ArrayList;
|
|
/**
|
|
* Holds logic for the keyboard views. This includes things like when to
|
|
* snap, when to switch keyboards, etc. It provides callbacks for when actions
|
|
* that need to be handled at the IME level occur (when text is entered, when
|
|
* the action should be performed).
|
|
*/
|
|
public class LeanbackKeyboardController implements LeanbackKeyboardContainer.VoiceListener,
|
|
LeanbackKeyboardContainer.DismissListener {
|
|
private static final String TAG = "LbKbController";
|
|
private static final boolean DEBUG = false;
|
|
|
|
/**
|
|
* The amount of time to block movement after a button down was detected.
|
|
*/
|
|
public static final int CLICK_MOVEMENT_BLOCK_DURATION_MS = 500;
|
|
|
|
/**
|
|
* The minimum distance in pixels before the view will transition to the
|
|
* move state.
|
|
*/
|
|
public float mResizeSquareDistance;
|
|
|
|
// keep track of the most recent key changes and their times so we can
|
|
// revert motion caused by clicking
|
|
private static final int KEY_CHANGE_HISTORY_SIZE = 10;
|
|
private static final long KEY_CHANGE_REVERT_TIME_MS = 100;
|
|
|
|
/**
|
|
* This listener reports high level actions that have occurred, such as
|
|
* text entry (from keys or voice) or the action button being pressed.
|
|
*/
|
|
public interface InputListener {
|
|
public static final int ENTRY_TYPE_STRING = 0;
|
|
public static final int ENTRY_TYPE_BACKSPACE = 1;
|
|
public static final int ENTRY_TYPE_SUGGESTION = 2;
|
|
public static final int ENTRY_TYPE_LEFT = 3;
|
|
public static final int ENTRY_TYPE_RIGHT = 4;
|
|
public static final int ENTRY_TYPE_ACTION = 5;
|
|
public static final int ENTRY_TYPE_VOICE = 6;
|
|
public static final int ENTRY_TYPE_DISMISS = 7;
|
|
public static final int ENTRY_TYPE_VOICE_DISMISS = 8;
|
|
|
|
/**
|
|
* Sent when the user has selected something that should affect the text
|
|
* field, such as entering a character, selecting the action, or
|
|
* finishing a voice action.
|
|
*
|
|
* @param type The type of key selected
|
|
* @param keyCode the key code of the key if applicable
|
|
* @param result The text entered if applicable
|
|
*/
|
|
public void onEntry(int type, int keyCode, CharSequence result);
|
|
}
|
|
|
|
private static final class KeyChange {
|
|
public long time;
|
|
public PointF position;
|
|
|
|
public KeyChange(long time, PointF position) {
|
|
this.time = time;
|
|
this.position = position;
|
|
}
|
|
}
|
|
|
|
private class DoubleClickDetector {
|
|
final long DOUBLE_CLICK_TIMEOUT_MS = 200;
|
|
long mFirstClickTime = 0;
|
|
boolean mFirstClickShiftLocked;
|
|
|
|
public void reset() {
|
|
mFirstClickTime = 0;
|
|
}
|
|
|
|
public void addEvent(long currTime) {
|
|
if (currTime - mFirstClickTime > DOUBLE_CLICK_TIMEOUT_MS) {
|
|
mFirstClickTime = currTime;
|
|
mFirstClickShiftLocked = mContainer.isCapsLockOn();
|
|
commitKey();
|
|
} else {
|
|
mContainer.onShiftDoubleClick(mFirstClickShiftLocked);
|
|
reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
private DoubleClickDetector mDoubleClickDetector = new DoubleClickDetector();
|
|
|
|
private View.OnLayoutChangeListener mOnLayoutChangeListener
|
|
= new View.OnLayoutChangeListener() {
|
|
|
|
@Override
|
|
public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
|
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
|
int w = right - left;
|
|
int h = bottom - top;
|
|
int oldW = oldRight - oldLeft;
|
|
int oldH = oldBottom - oldTop;
|
|
if (w > 0 && h > 0) {
|
|
if (w != oldW || h != oldH) {
|
|
initInputView();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
private InputMethodService mContext;
|
|
private InputListener mInputListener;
|
|
private LeanbackKeyboardContainer mContainer;
|
|
|
|
private LeanbackKeyboardContainer.KeyFocus mDownFocus =
|
|
new LeanbackKeyboardContainer.KeyFocus();
|
|
private LeanbackKeyboardContainer.KeyFocus mTempFocus =
|
|
new LeanbackKeyboardContainer.KeyFocus();
|
|
|
|
ArrayList<KeyChange> mKeyChangeHistory = new ArrayList<KeyChange>(KEY_CHANGE_HISTORY_SIZE + 1);
|
|
private PointF mTempPoint = new PointF();
|
|
|
|
private boolean mKeyDownReceived = false;
|
|
private boolean mLongPressHandled = false;
|
|
private KeyFocus mKeyDownKeyFocus;
|
|
private int mMoveCount;
|
|
|
|
public LeanbackKeyboardController(InputMethodService context, InputListener listener) {
|
|
this(context, listener, new LeanbackKeyboardContainer(context));
|
|
}
|
|
|
|
LeanbackKeyboardController(InputMethodService context, InputListener listener,
|
|
LeanbackKeyboardContainer container) {
|
|
mContext = context;
|
|
mResizeSquareDistance = context.getResources().getDimension(R.dimen.resize_move_distance);
|
|
mResizeSquareDistance *= mResizeSquareDistance;
|
|
mInputListener = listener;
|
|
setKeyboardContainer(container);
|
|
mContainer.setVoiceListener(this);
|
|
mContainer.setDismissListener(this);
|
|
}
|
|
|
|
/**
|
|
* This method is called when we start the input at a NEW input field.
|
|
*/
|
|
public void onStartInput(EditorInfo attribute) {
|
|
if (mContainer != null) {
|
|
mContainer.onStartInput(attribute);
|
|
initInputView();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method is called by whenever we bring up the IME at an input field.
|
|
*/
|
|
public void onStartInputView() {
|
|
mKeyDownReceived = false;
|
|
if (mContainer != null) {
|
|
mContainer.onStartInputView();
|
|
}
|
|
mDoubleClickDetector.reset();
|
|
}
|
|
|
|
/**
|
|
* This method sets the pixel positions in mSpaceTracker to match the
|
|
* current KeyFocus in {@link LeanbackKeyboardContainer} This method is called
|
|
* when the keyboard layout is complete, after
|
|
* {@link LeanbackKeyboardContainer.onInitInputView}, to initialize the starting
|
|
* position of mSpaceTracker; and in onUp to reset the pixel position in
|
|
* mSpaceTracker.
|
|
*/
|
|
private void updatePositionToCurrentFocus() {
|
|
PointF currPosition = getCurrentKeyPosition();
|
|
if (currPosition != null) {
|
|
}
|
|
}
|
|
|
|
private void initInputView() {
|
|
mContainer.onInitInputView();
|
|
updatePositionToCurrentFocus();
|
|
}
|
|
|
|
private PointF getCurrentKeyPosition() {
|
|
if (mContainer != null) {
|
|
LeanbackKeyboardContainer.KeyFocus initialKeyInfo = mContainer.getCurrFocus();
|
|
return new PointF(initialKeyInfo.rect.centerX(), initialKeyInfo.rect.centerY());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void performBestSnap(long time) {
|
|
KeyFocus focus = mContainer.getCurrFocus();
|
|
mTempPoint.x = focus.rect.centerX();
|
|
mTempPoint.y = focus.rect.centerY();
|
|
PointF bestSnap = getBestSnapPosition(mTempPoint, time);
|
|
mContainer.getBestFocus(bestSnap.x, bestSnap.y, mTempFocus);
|
|
mContainer.setFocus(mTempFocus);
|
|
updatePositionToCurrentFocus();
|
|
}
|
|
|
|
private PointF getBestSnapPosition(PointF currPoint, long currTime) {
|
|
if (mKeyChangeHistory.size() <= 1) {
|
|
return currPoint;
|
|
}
|
|
for (int i = 0; i < mKeyChangeHistory.size() - 1; i++) {
|
|
KeyChange change = mKeyChangeHistory.get(i);
|
|
KeyChange nextChange = mKeyChangeHistory.get(i + 1);
|
|
if (currTime - nextChange.time < KEY_CHANGE_REVERT_TIME_MS) {
|
|
if (DEBUG) {
|
|
Log.d(TAG, "Reverting keychange to " + change.position.toString());
|
|
}
|
|
// Return the oldest key change within the revert window and
|
|
// clear all key changes
|
|
currPoint = change.position;
|
|
// on a revert, clear the history and add the reverting point.
|
|
// This way the reverted point will be preferred if there's
|
|
// another fast change before the next call.
|
|
mKeyChangeHistory.clear();
|
|
mKeyChangeHistory.add(new KeyChange(currTime, currPoint));
|
|
break;
|
|
}
|
|
}
|
|
return currPoint;
|
|
}
|
|
|
|
public void setKeyboardContainer(LeanbackKeyboardContainer container) {
|
|
mContainer = container;
|
|
container.getView().addOnLayoutChangeListener(mOnLayoutChangeListener);
|
|
}
|
|
|
|
public View getView() {
|
|
if (mContainer != null) {
|
|
return mContainer.getView();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public boolean areSuggestionsEnabled() {
|
|
if (mContainer != null) {
|
|
return mContainer.areSuggestionsEnabled();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean enableAutoEnterSpace() {
|
|
if (mContainer != null) {
|
|
return mContainer.enableAutoEnterSpace();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
mDownFocus.set(mContainer.getCurrFocus());
|
|
// this will handle other events, e.g. hardware keyboard
|
|
if (isEnterKey(keyCode)) {
|
|
mKeyDownReceived = true;
|
|
// first keyDown
|
|
if (event.getRepeatCount() == 0) {
|
|
mContainer.setTouchState(LeanbackKeyboardContainer.TOUCH_STATE_CLICK);
|
|
}
|
|
}
|
|
|
|
return handleKeyDownEvent(keyCode, event.getRepeatCount());
|
|
}
|
|
|
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
|
// this only handles InputDevice.SOURCE_TOUCH_NAVIGATION events
|
|
if (isEnterKey(keyCode)) {
|
|
if (!mKeyDownReceived || mLongPressHandled) {
|
|
mLongPressHandled = false;
|
|
return true;
|
|
}
|
|
mKeyDownReceived = false;
|
|
if (mContainer.getTouchState() == LeanbackKeyboardContainer.TOUCH_STATE_CLICK) {
|
|
mContainer.setTouchState(LeanbackKeyboardContainer.TOUCH_STATE_TOUCH_SNAP);
|
|
}
|
|
}
|
|
return handleKeyUpEvent(keyCode, event.getEventTime());
|
|
}
|
|
|
|
public boolean onGenericMotionEvent(MotionEvent event) {
|
|
return false;
|
|
}
|
|
|
|
private boolean onDirectionalMove(int dir) {
|
|
if (mContainer.getNextFocusInDirection(dir, mDownFocus, mTempFocus)) {
|
|
mContainer.setFocus(mTempFocus);
|
|
mDownFocus.set(mTempFocus);
|
|
|
|
clearKeyIfNecessary();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void clearKeyIfNecessary() {
|
|
mMoveCount++;
|
|
if (mMoveCount >= 3) {
|
|
mMoveCount = 0;
|
|
mKeyDownKeyFocus = null;
|
|
}
|
|
}
|
|
|
|
private void commitKey() {
|
|
commitKey(mContainer.getCurrFocus());
|
|
}
|
|
|
|
private void commitKey(LeanbackKeyboardContainer.KeyFocus keyFocus) {
|
|
if (mContainer == null || keyFocus == null) {
|
|
return;
|
|
}
|
|
|
|
switch (keyFocus.type) {
|
|
case KeyFocus.TYPE_VOICE:
|
|
// voice doesn't have to go through the IME
|
|
mContainer.onVoiceClick();
|
|
break;
|
|
case KeyFocus.TYPE_ACTION:
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_ACTION, 0, null);
|
|
break;
|
|
case KeyFocus.TYPE_SUGGESTION:
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_SUGGESTION, 0,
|
|
mContainer.getSuggestionText(keyFocus.index));
|
|
break;
|
|
default:
|
|
Key key = mContainer.getKey(keyFocus.type, keyFocus.index);
|
|
if (key != null) {
|
|
int code = key.codes[0];
|
|
CharSequence label = key.label;
|
|
handleCommitKeyboardKey(code, label);
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
private void handleCommitKeyboardKey(int code, CharSequence label) {
|
|
switch (code) {
|
|
case Keyboard.KEYCODE_MODE_CHANGE:
|
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
|
Log.d(TAG, "mode change");
|
|
}
|
|
mContainer.onModeChangeClick();
|
|
break;
|
|
case LeanbackKeyboardView.KEYCODE_CAPS_LOCK:
|
|
mContainer.onShiftDoubleClick(mContainer.isCapsLockOn());
|
|
break;
|
|
case Keyboard.KEYCODE_SHIFT:
|
|
// TODO invalidate and draw a different shift
|
|
// key in the function keyboard
|
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
|
Log.d(TAG, "shift");
|
|
}
|
|
mContainer.onShiftClick();
|
|
break;
|
|
case LeanbackKeyboardView.KEYCODE_DISMISS_MINI_KEYBOARD:
|
|
mContainer.dismissMiniKeyboard();
|
|
break;
|
|
case LeanbackKeyboardView.KEYCODE_LEFT:
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_LEFT, 0, null);
|
|
break;
|
|
case LeanbackKeyboardView.KEYCODE_RIGHT:
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_RIGHT, 0, null);
|
|
break;
|
|
case Keyboard.KEYCODE_DELETE:
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_BACKSPACE, 0, null);
|
|
break;
|
|
case LeanbackKeyboardView.ASCII_SPACE:
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_STRING, code, " ");
|
|
mContainer.onSpaceEntry();
|
|
break;
|
|
case LeanbackKeyboardView.ASCII_PERIOD:
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_STRING, code, label);
|
|
mContainer.onPeriodEntry();
|
|
break;
|
|
case LeanbackKeyboardView.KEYCODE_VOICE:
|
|
mContainer.startVoiceRecording();
|
|
break;
|
|
// fall through to default with this label
|
|
default:
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_STRING, code, label);
|
|
mContainer.onTextEntry();
|
|
|
|
if (mContainer.isMiniKeyboardOnScreen()) {
|
|
mContainer.dismissMiniKeyboard();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private boolean handleKeyDownEvent(int keyCode, int eventRepeatCount) {
|
|
keyCode = getSimplifiedKey(keyCode);
|
|
|
|
// never trap back
|
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
mContainer.cancelVoiceRecording();
|
|
return false;
|
|
}
|
|
|
|
// capture all key downs when voice is visible
|
|
if (mContainer.isVoiceVisible()) {
|
|
if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
|
mContainer.cancelVoiceRecording();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
boolean handled = true;
|
|
switch(keyCode) {
|
|
// Direction keys are handled on down to allow repeated movement
|
|
case KeyEvent.KEYCODE_DPAD_LEFT:
|
|
handled = onDirectionalMove(LeanbackKeyboardContainer.DIRECTION_LEFT);
|
|
break;
|
|
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
|
handled = onDirectionalMove(LeanbackKeyboardContainer.DIRECTION_RIGHT);
|
|
break;
|
|
case KeyEvent.KEYCODE_DPAD_UP:
|
|
handled = onDirectionalMove(LeanbackKeyboardContainer.DIRECTION_UP);
|
|
break;
|
|
case KeyEvent.KEYCODE_DPAD_DOWN:
|
|
handled = onDirectionalMove(LeanbackKeyboardContainer.DIRECTION_DOWN);
|
|
break;
|
|
case KeyEvent.KEYCODE_BUTTON_X:
|
|
handleCommitKeyboardKey(Keyboard.KEYCODE_DELETE, null);
|
|
break;
|
|
case KeyEvent.KEYCODE_BUTTON_Y:
|
|
handleCommitKeyboardKey(LeanbackKeyboardView.ASCII_SPACE, null);
|
|
break;
|
|
case KeyEvent.KEYCODE_BUTTON_L1:
|
|
handleCommitKeyboardKey(LeanbackKeyboardView.KEYCODE_LEFT, null);
|
|
break;
|
|
case KeyEvent.KEYCODE_BUTTON_R1:
|
|
handleCommitKeyboardKey(LeanbackKeyboardView.KEYCODE_RIGHT, null);
|
|
break;
|
|
// these are handled on up
|
|
case KeyEvent.KEYCODE_DPAD_CENTER:
|
|
if (eventRepeatCount == 0) {
|
|
mMoveCount = 0;
|
|
mKeyDownKeyFocus = new KeyFocus();
|
|
mKeyDownKeyFocus.set(mContainer.getCurrFocus());
|
|
} else if (eventRepeatCount == 1) {
|
|
if (handleKeyLongPress(keyCode)) {
|
|
mKeyDownKeyFocus = null;
|
|
}
|
|
}
|
|
|
|
if (isKeyHandledOnKeyDown(mContainer.getCurrKeyCode())) {
|
|
commitKey();
|
|
}
|
|
break;
|
|
// also handled on up
|
|
case KeyEvent.KEYCODE_BUTTON_THUMBL:
|
|
case KeyEvent.KEYCODE_BUTTON_THUMBR:
|
|
case KeyEvent.KEYCODE_ENTER:
|
|
break;
|
|
default:
|
|
handled = false;
|
|
break;
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
private boolean handleKeyLongPress(int keyCode) {
|
|
mLongPressHandled = isEnterKey(keyCode) && mContainer.onKeyLongPress();
|
|
if (mContainer.isMiniKeyboardOnScreen()) {
|
|
Log.d(TAG, "mini keyboard shown after long press");
|
|
}
|
|
return mLongPressHandled;
|
|
}
|
|
|
|
private boolean isKeyHandledOnKeyDown(int currKeyCode) {
|
|
return currKeyCode == Keyboard.KEYCODE_DELETE
|
|
|| currKeyCode == LeanbackKeyboardView.KEYCODE_LEFT
|
|
|| currKeyCode == LeanbackKeyboardView.KEYCODE_RIGHT;
|
|
}
|
|
|
|
/**
|
|
* This handles all key events from an input device
|
|
* @param keyCode
|
|
* @return true if the key was handled, false otherwise
|
|
*/
|
|
private boolean handleKeyUpEvent(int keyCode, long currTime) {
|
|
keyCode = getSimplifiedKey(keyCode);
|
|
|
|
// never trap back
|
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
return false;
|
|
}
|
|
|
|
// capture all key ups when voice is visible
|
|
if (mContainer.isVoiceVisible()) {
|
|
return true;
|
|
}
|
|
|
|
boolean handled = true;
|
|
switch(keyCode) {
|
|
// Some keys are handled on down to allow repeats
|
|
case KeyEvent.KEYCODE_DPAD_LEFT:
|
|
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
|
case KeyEvent.KEYCODE_DPAD_UP:
|
|
case KeyEvent.KEYCODE_DPAD_DOWN:
|
|
clearKeyIfNecessary();
|
|
break;
|
|
case KeyEvent.KEYCODE_BUTTON_X:
|
|
case KeyEvent.KEYCODE_BUTTON_Y:
|
|
case KeyEvent.KEYCODE_BUTTON_L1:
|
|
case KeyEvent.KEYCODE_BUTTON_R1:
|
|
break;
|
|
case KeyEvent.KEYCODE_DPAD_CENTER:
|
|
if (mContainer.getCurrKeyCode() == Keyboard.KEYCODE_SHIFT) {
|
|
mDoubleClickDetector.addEvent(currTime);
|
|
} else if (!isKeyHandledOnKeyDown(mContainer.getCurrKeyCode())) {
|
|
commitKey(mKeyDownKeyFocus);
|
|
}
|
|
break;
|
|
case KeyEvent.KEYCODE_BUTTON_THUMBL:
|
|
handleCommitKeyboardKey(Keyboard.KEYCODE_MODE_CHANGE, null);
|
|
break;
|
|
case KeyEvent.KEYCODE_BUTTON_THUMBR:
|
|
handleCommitKeyboardKey(LeanbackKeyboardView.KEYCODE_CAPS_LOCK, null);
|
|
break;
|
|
case KeyEvent.KEYCODE_ENTER:
|
|
if (mContainer != null) {
|
|
KeyFocus keyFocus = mContainer.getCurrFocus();
|
|
if (keyFocus != null && keyFocus.type == KeyFocus.TYPE_SUGGESTION) {
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_SUGGESTION, 0,
|
|
mContainer.getSuggestionText(keyFocus.index));
|
|
}
|
|
}
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_DISMISS, 0, null);
|
|
break;
|
|
default:
|
|
handled = false;
|
|
break;
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
public void updateSuggestions(ArrayList<String> suggestions) {
|
|
if (mContainer != null) {
|
|
mContainer.updateSuggestions(suggestions);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onVoiceResult(String result) {
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_VOICE, 0, result);
|
|
}
|
|
|
|
@Override
|
|
public void onDismiss(boolean fromVoice) {
|
|
if (fromVoice) {
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_VOICE_DISMISS, 0, null);
|
|
} else {
|
|
mInputListener.onEntry(InputListener.ENTRY_TYPE_DISMISS, 0, null);
|
|
}
|
|
}
|
|
|
|
private boolean isEnterKey(int keyCode) {
|
|
return getSimplifiedKey(keyCode) == KeyEvent.KEYCODE_DPAD_CENTER;
|
|
}
|
|
|
|
private int getSimplifiedKey(int keyCode) {
|
|
// simplify for dpad center
|
|
keyCode = (keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
|
|
keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER ||
|
|
keyCode == KeyEvent.KEYCODE_BUTTON_A) ? KeyEvent.KEYCODE_DPAD_CENTER : keyCode;
|
|
|
|
// simply for back
|
|
keyCode = (keyCode == KeyEvent.KEYCODE_BUTTON_B ? KeyEvent.KEYCODE_BACK : keyCode);
|
|
|
|
return keyCode;
|
|
}
|
|
}
|