am 678a1252: Split up the event synthesis code by source.
* commit '678a1252b4f3cdc18d20b411c05a4320d1d9b719': Split up the event synthesis code by source.
This commit is contained in:
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 android.view;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This class creates DPAD events from TouchNavigation events.
|
||||
*
|
||||
* @see ViewRootImpl
|
||||
*/
|
||||
|
||||
//TODO: Make this class an internal class of ViewRootImpl.java
|
||||
class SimulatedDpad {
|
||||
|
||||
private static final String TAG = "SimulatedDpad";
|
||||
|
||||
// Maximum difference in milliseconds between the down and up of a touch
|
||||
// event for it to be considered a tap
|
||||
// TODO:Read this value from a configuration file
|
||||
private static final int MAX_TAP_TIME = 250;
|
||||
// Where the cutoff is for determining an edge swipe
|
||||
private static final float EDGE_SWIPE_THRESHOLD = 0.9f;
|
||||
private static final int MSG_FLICK = 313;
|
||||
// TODO: Pass touch slop from the input device
|
||||
private static final int TOUCH_SLOP = 30;
|
||||
// The position of the previous TouchNavigation event
|
||||
private float mLastTouchNavigationXPosition;
|
||||
private float mLastTouchNavigationYPosition;
|
||||
// Where the Touch Navigation was initially pressed
|
||||
private float mTouchNavigationEnterXPosition;
|
||||
private float mTouchNavigationEnterYPosition;
|
||||
// When the most recent ACTION_HOVER_ENTER occurred
|
||||
private long mLastTouchNavigationStartTimeMs = 0;
|
||||
// When the most recent direction key was sent
|
||||
private long mLastTouchNavigationKeySendTimeMs = 0;
|
||||
// When the most recent touch event of any type occurred
|
||||
private long mLastTouchNavigationEventTimeMs = 0;
|
||||
// Did the swipe begin in a valid region
|
||||
private boolean mEdgeSwipePossible;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
// How quickly keys were sent;
|
||||
private int mKeySendRateMs = 0;
|
||||
private int mLastKeySent;
|
||||
// Last movement in device screen pixels
|
||||
private float mLastMoveX = 0;
|
||||
private float mLastMoveY = 0;
|
||||
// Offset from the initial touch. Gets reset as direction keys are sent.
|
||||
private float mAccumulatedX;
|
||||
private float mAccumulatedY;
|
||||
|
||||
// Change in position allowed during tap events
|
||||
private float mTouchSlop;
|
||||
private float mTouchSlopSquared;
|
||||
// Has the TouchSlop constraint been invalidated
|
||||
private boolean mAlwaysInTapRegion = true;
|
||||
|
||||
// Information from the most recent event.
|
||||
// Used to determine what device sent the event during a fling.
|
||||
private int mLastSource;
|
||||
private int mLastMetaState;
|
||||
private int mLastDeviceId;
|
||||
|
||||
// TODO: Currently using screen dimensions tuned to a Galaxy Nexus, need to
|
||||
// read this from a config file instead
|
||||
private int mDistancePerTick;
|
||||
private int mDistancePerTickSquared;
|
||||
// Highest rate that the flinged events can occur at before dying out
|
||||
private int mMaxRepeatDelay;
|
||||
// The square of the minimum distance needed for a flick to register
|
||||
private int mMinFlickDistanceSquared;
|
||||
// How quickly the repeated events die off
|
||||
private float mFlickDecay;
|
||||
|
||||
public SimulatedDpad(Context context) {
|
||||
mDistancePerTick = SystemProperties.getInt("persist.vr_dist_tick", 64);
|
||||
mDistancePerTickSquared = mDistancePerTick * mDistancePerTick;
|
||||
mMaxRepeatDelay = SystemProperties.getInt("persist.vr_repeat_delay", 300);
|
||||
mMinFlickDistanceSquared = SystemProperties.getInt("persist.vr_min_flick", 20);
|
||||
mMinFlickDistanceSquared *= mMinFlickDistanceSquared;
|
||||
mFlickDecay = Float.parseFloat(SystemProperties.get(
|
||||
"persist.sys.vr_flick_decay", "1.3"));
|
||||
mTouchSlop = TOUCH_SLOP;
|
||||
mTouchSlopSquared = mTouchSlop * mTouchSlop;
|
||||
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
private final Handler mHandler = new Handler(true /*async*/) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_FLICK: {
|
||||
final long time = SystemClock.uptimeMillis();
|
||||
ViewRootImpl viewroot = (ViewRootImpl) msg.obj;
|
||||
// Send the key
|
||||
viewroot.enqueueInputEvent(new KeyEvent(time, time,
|
||||
KeyEvent.ACTION_DOWN, msg.arg2, 0, mLastMetaState,
|
||||
mLastDeviceId, 0, KeyEvent.FLAG_FALLBACK, mLastSource));
|
||||
viewroot.enqueueInputEvent(new KeyEvent(time, time,
|
||||
KeyEvent.ACTION_UP, msg.arg2, 0, mLastMetaState,
|
||||
mLastDeviceId, 0, KeyEvent.FLAG_FALLBACK, mLastSource));
|
||||
|
||||
// Increase the delay by the decay factor and resend
|
||||
final int delay = (int) Math.ceil(mFlickDecay * msg.arg1);
|
||||
if (delay <= mMaxRepeatDelay) {
|
||||
Message msgCopy = Message.obtain(msg);
|
||||
msgCopy.arg1 = delay;
|
||||
msgCopy.setAsynchronous(true);
|
||||
mHandler.sendMessageDelayed(msgCopy, delay);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void updateTouchNavigation(ViewRootImpl viewroot, MotionEvent event,
|
||||
boolean synthesizeNewKeys) {
|
||||
if (!synthesizeNewKeys) {
|
||||
mHandler.removeMessages(MSG_FLICK);
|
||||
}
|
||||
InputDevice device = event.getDevice();
|
||||
if (device == null) {
|
||||
return;
|
||||
}
|
||||
// Store what time the TouchNavigation event occurred
|
||||
final long time = SystemClock.uptimeMillis();
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mLastTouchNavigationStartTimeMs = time;
|
||||
mAlwaysInTapRegion = true;
|
||||
mTouchNavigationEnterXPosition = event.getX();
|
||||
mTouchNavigationEnterYPosition = event.getY();
|
||||
mAccumulatedX = 0;
|
||||
mAccumulatedY = 0;
|
||||
mLastMoveX = 0;
|
||||
mLastMoveY = 0;
|
||||
if (device.getMotionRange(MotionEvent.AXIS_Y).getMax()
|
||||
* EDGE_SWIPE_THRESHOLD < event.getY()) {
|
||||
// Did the swipe begin in a valid region
|
||||
mEdgeSwipePossible = true;
|
||||
}
|
||||
// Clear any flings
|
||||
if (synthesizeNewKeys) {
|
||||
mHandler.removeMessages(MSG_FLICK);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
// Determine whether the move is slop or an intentional move
|
||||
float deltaX = event.getX() - mTouchNavigationEnterXPosition;
|
||||
float deltaY = event.getY() - mTouchNavigationEnterYPosition;
|
||||
if (mTouchSlopSquared < deltaX * deltaX + deltaY * deltaY) {
|
||||
mAlwaysInTapRegion = false;
|
||||
}
|
||||
// Checks if the swipe has crossed the midpoint
|
||||
// and if our swipe gesture is complete
|
||||
if (event.getY() < (device.getMotionRange(MotionEvent.AXIS_Y).getMax()
|
||||
* .5) && mEdgeSwipePossible) {
|
||||
mEdgeSwipePossible = false;
|
||||
|
||||
Intent intent =
|
||||
((SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE))
|
||||
.getAssistIntent(mContext, false, UserHandle.USER_CURRENT_OR_SELF);
|
||||
if (intent != null) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
try {
|
||||
mContext.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e){
|
||||
Log.e(TAG, "Could not start search activity");
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Could not find a search activity");
|
||||
}
|
||||
}
|
||||
// Find the difference in position between the two most recent
|
||||
// TouchNavigation events
|
||||
mLastMoveX = event.getX() - mLastTouchNavigationXPosition;
|
||||
mLastMoveY = event.getY() - mLastTouchNavigationYPosition;
|
||||
mAccumulatedX += mLastMoveX;
|
||||
mAccumulatedY += mLastMoveY;
|
||||
float mAccumulatedXSquared = mAccumulatedX * mAccumulatedX;
|
||||
float mAccumulatedYSquared = mAccumulatedY * mAccumulatedY;
|
||||
// Determine if we've moved far enough to send a key press
|
||||
if (mAccumulatedXSquared > mDistancePerTickSquared ||
|
||||
mAccumulatedYSquared > mDistancePerTickSquared) {
|
||||
float dominantAxis;
|
||||
float sign;
|
||||
boolean isXAxis;
|
||||
int key;
|
||||
int repeatCount = 0;
|
||||
// Determine dominant axis
|
||||
if (mAccumulatedXSquared > mAccumulatedYSquared) {
|
||||
dominantAxis = mAccumulatedX;
|
||||
isXAxis = true;
|
||||
} else {
|
||||
dominantAxis = mAccumulatedY;
|
||||
isXAxis = false;
|
||||
}
|
||||
// Determine sign of axis
|
||||
sign = (dominantAxis > 0) ? 1 : -1;
|
||||
// Determine key to send
|
||||
if (isXAxis) {
|
||||
key = (sign == 1) ? KeyEvent.KEYCODE_DPAD_RIGHT :
|
||||
KeyEvent.KEYCODE_DPAD_LEFT;
|
||||
} else {
|
||||
key = (sign == 1) ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
|
||||
}
|
||||
// Send key until maximum distance constraint is satisfied
|
||||
while (dominantAxis * dominantAxis > mDistancePerTickSquared) {
|
||||
repeatCount++;
|
||||
dominantAxis -= sign * mDistancePerTick;
|
||||
if (synthesizeNewKeys) {
|
||||
viewroot.enqueueInputEvent(new KeyEvent(time, time,
|
||||
KeyEvent.ACTION_DOWN, key, 0, event.getMetaState(),
|
||||
event.getDeviceId(), 0, KeyEvent.FLAG_FALLBACK,
|
||||
event.getSource()));
|
||||
viewroot.enqueueInputEvent(new KeyEvent(time, time,
|
||||
KeyEvent.ACTION_UP, key, 0, event.getMetaState(),
|
||||
event.getDeviceId(), 0, KeyEvent.FLAG_FALLBACK,
|
||||
event.getSource()));
|
||||
}
|
||||
}
|
||||
// Save new axis values
|
||||
mAccumulatedX = isXAxis ? dominantAxis : 0;
|
||||
mAccumulatedY = isXAxis ? 0 : dominantAxis;
|
||||
|
||||
mLastKeySent = key;
|
||||
mKeySendRateMs = (int) (time - mLastTouchNavigationKeySendTimeMs) / repeatCount;
|
||||
mLastTouchNavigationKeySendTimeMs = time;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (time - mLastTouchNavigationStartTimeMs < MAX_TAP_TIME && mAlwaysInTapRegion) {
|
||||
if (synthesizeNewKeys) {
|
||||
viewroot.enqueueInputEvent(new KeyEvent(mLastTouchNavigationStartTimeMs,
|
||||
time, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0,
|
||||
event.getMetaState(), event.getDeviceId(), 0,
|
||||
KeyEvent.FLAG_FALLBACK, event.getSource()));
|
||||
viewroot.enqueueInputEvent(new KeyEvent(mLastTouchNavigationStartTimeMs,
|
||||
time, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0,
|
||||
event.getMetaState(), event.getDeviceId(), 0,
|
||||
KeyEvent.FLAG_FALLBACK, event.getSource()));
|
||||
}
|
||||
} else {
|
||||
float xMoveSquared = mLastMoveX * mLastMoveX;
|
||||
float yMoveSquared = mLastMoveY * mLastMoveY;
|
||||
// Determine whether the last gesture was a fling.
|
||||
if (mMinFlickDistanceSquared <= xMoveSquared + yMoveSquared &&
|
||||
time - mLastTouchNavigationEventTimeMs <= MAX_TAP_TIME &&
|
||||
mKeySendRateMs <= mMaxRepeatDelay && mKeySendRateMs > 0) {
|
||||
mLastDeviceId = event.getDeviceId();
|
||||
mLastSource = event.getSource();
|
||||
mLastMetaState = event.getMetaState();
|
||||
|
||||
if (synthesizeNewKeys) {
|
||||
Message message = Message.obtain(mHandler, MSG_FLICK,
|
||||
mKeySendRateMs, mLastKeySent, viewroot);
|
||||
message.setAsynchronous(true);
|
||||
mHandler.sendMessageDelayed(message, mKeySendRateMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
mEdgeSwipePossible = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Store touch event position and time
|
||||
mLastTouchNavigationEventTimeMs = time;
|
||||
mLastTouchNavigationXPosition = event.getX();
|
||||
mLastTouchNavigationYPosition = event.getY();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user