diff options
author | Jeff Brown <jeffbrown@android.com> | 2011-05-31 15:42:18 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-05-31 15:42:18 -0700 |
commit | c272d4279493000928b8b7c6dbcf2d2b7d8d08b2 (patch) | |
tree | 63921d7f9beaa9580876bdacca8df46e4bcc38e7 | |
parent | d854304c2bcadbda37a7f1b24723dbc0030073ca (diff) | |
parent | 214eaf48878bba00cbd5831871bcbd82632b6e34 (diff) | |
download | frameworks_base-c272d4279493000928b8b7c6dbcf2d2b7d8d08b2.zip frameworks_base-c272d4279493000928b8b7c6dbcf2d2b7d8d08b2.tar.gz frameworks_base-c272d4279493000928b8b7c6dbcf2d2b7d8d08b2.tar.bz2 |
Merge "Use ViewConfiguration to seed input system configuration." into honeycomb-mr2
-rw-r--r-- | services/input/InputDispatcher.cpp | 37 | ||||
-rw-r--r-- | services/input/InputDispatcher.h | 46 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 175 | ||||
-rw-r--r-- | services/input/InputReader.h | 136 | ||||
-rw-r--r-- | services/input/tests/InputDispatcher_test.cpp | 14 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 32 | ||||
-rw-r--r-- | services/java/com/android/server/wm/InputManager.java | 20 | ||||
-rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 215 |
8 files changed, 384 insertions, 291 deletions
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 9a77af3..5ea12c7 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -222,13 +222,14 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mKeyRepeatState.lastKeyEntry = NULL; - int32_t maxEventsPerSecond = policy->getMaxEventsPerSecond(); - mThrottleState.minTimeBetweenEvents = 1000000000LL / maxEventsPerSecond; + policy->getDispatcherConfiguration(&mConfig); + + mThrottleState.minTimeBetweenEvents = 1000000000LL / mConfig.maxEventsPerSecond; mThrottleState.lastDeviceId = -1; #if DEBUG_THROTTLING mThrottleState.originalSampleCount = 0; - LOGD("Throttling - Max events per second = %d", maxEventsPerSecond); + LOGD("Throttling - Max events per second = %d", mConfig.maxEventsPerSecond); #endif } @@ -247,13 +248,10 @@ InputDispatcher::~InputDispatcher() { } void InputDispatcher::dispatchOnce() { - nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout(); - nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay(); - nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); - dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime); + dispatchOnceInnerLocked(&nextWakeupTime); if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately @@ -266,14 +264,13 @@ void InputDispatcher::dispatchOnce() { mLooper->pollOnce(timeoutMillis); } -void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, - nsecs_t keyRepeatDelay, nsecs_t* nextWakeupTime) { +void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); // Reset the key repeat timer whenever we disallow key events, even if the next event // is not a key. This is to ensure that we abort a key repeat if the device is just coming // out of sleep. - if (keyRepeatTimeout < 0) { + if (!mPolicy->isKeyRepeatEnabled()) { resetKeyRepeatLocked(); } @@ -307,7 +304,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, // Synthesize a key repeat if appropriate. if (mKeyRepeatState.lastKeyEntry) { if (currentTime >= mKeyRepeatState.nextRepeatTime) { - mPendingEvent = synthesizeKeyRepeatLocked(currentTime, keyRepeatDelay); + mPendingEvent = synthesizeKeyRepeatLocked(currentTime); } else { if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { *nextWakeupTime = mKeyRepeatState.nextRepeatTime; @@ -426,8 +423,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } - done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, - &dropReason, nextWakeupTime); + done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } @@ -686,8 +682,7 @@ void InputDispatcher::resetKeyRepeatLocked() { } } -InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked( - nsecs_t currentTime, nsecs_t keyRepeatDelay) { +InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { KeyEntry* entry = mKeyRepeatState.lastKeyEntry; // Reuse the repeated key entry if it is otherwise unreferenced. @@ -715,7 +710,7 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked( // mKeyRepeatState.lastKeyEntry in addition to the one we return. entry->refCount += 1; - mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatDelay; + mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; return entry; } @@ -735,8 +730,7 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( return true; } -bool InputDispatcher::dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, +bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. if (! entry->dispatchInProgress) { @@ -756,7 +750,7 @@ bool InputDispatcher::dispatchKeyLocked( } else { // Not a repeat. Save key down state in case we do see a repeat later. resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout; + mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout; } mKeyRepeatState.lastKeyEntry = entry; entry->refCount += 1; @@ -3510,6 +3504,11 @@ void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const void InputDispatcher::dump(String8& dump) { dump.append("Input Dispatcher State:\n"); dumpDispatchStateLocked(dump); + + dump.append(INDENT "Configuration:\n"); + dump.appendFormat(INDENT2 "MaxEventsPerSecond: %d\n", mConfig.maxEventsPerSecond); + dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f); + dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f); } diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 39fa203..5631ef9 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -123,6 +123,30 @@ struct InputTarget { /* + * Input dispatcher configuration. + * + * Specifies various options that modify the behavior of the input dispatcher. + */ +struct InputDispatcherConfiguration { + // The key repeat initial timeout. + nsecs_t keyRepeatTimeout; + + // The key repeat inter-key delay. + nsecs_t keyRepeatDelay; + + // The maximum suggested event delivery rate per second. + // This value is used to throttle motion event movement actions on a per-device + // basis. It is not intended to be a hard limit. + int32_t maxEventsPerSecond; + + InputDispatcherConfiguration() : + keyRepeatTimeout(500 * 1000000LL), + keyRepeatDelay(50 * 1000000LL), + maxEventsPerSecond(60) { } +}; + + +/* * Input dispatcher policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager @@ -148,17 +172,11 @@ public: /* Notifies the system that an input channel is unrecoverably broken. */ virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0; - /* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */ - virtual nsecs_t getKeyRepeatTimeout() = 0; - - /* Gets the key repeat inter-key delay. */ - virtual nsecs_t getKeyRepeatDelay() = 0; + /* Gets the input dispatcher configuration. */ + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; - /* Gets the maximum suggested event delivery rate per second. - * This value is used to throttle motion event movement actions on a per-device - * basis. It is not intended to be a hard limit. - */ - virtual int32_t getMaxEventsPerSecond() = 0; + /* Returns true if automatic key repeating is enabled. */ + virtual bool isKeyRepeatEnabled() = 0; /* Intercepts a key event immediately before queueing it. * The policy can use this method as an opportunity to perform power management functions @@ -757,6 +775,7 @@ private: }; sp<InputDispatcherPolicyInterface> mPolicy; + InputDispatcherConfiguration mConfig; Mutex mLock; @@ -769,8 +788,7 @@ private: Vector<EventEntry*> mTempCancelationEvents; - void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay, - nsecs_t* nextWakeupTime); + void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); // Batches a new sample onto a motion entry. // Assumes that the we have already checked that we can append samples. @@ -842,7 +860,7 @@ private: } mKeyRepeatState; void resetKeyRepeatLocked(); - KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime, nsecs_t keyRepeatTimeout); + KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime); // Deferred command processing. bool runCommandsLockedInterruptible(); @@ -899,7 +917,7 @@ private: bool dispatchConfigurationChangedLocked( nsecs_t currentTime, ConfigurationChangedEntry* entry); bool dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, + nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime); bool dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 155fd2d..f2b34dd 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -56,67 +56,6 @@ namespace android { -// --- Constants --- - -// Quiet time between certain gesture transitions. -// Time to allow for all fingers or buttons to settle into a stable state before -// starting a new gesture. -static const nsecs_t QUIET_INTERVAL = 100 * 1000000; // 100 ms - -// The minimum speed that a pointer must travel for us to consider switching the active -// touch pointer to it during a drag. This threshold is set to avoid switching due -// to noise from a finger resting on the touch pad (perhaps just pressing it down). -static const float DRAG_MIN_SWITCH_SPEED = 50.0f; // pixels per second - -// Tap gesture delay time. -// The time between down and up must be less than this to be considered a tap. -static const nsecs_t TAP_INTERVAL = 150 * 1000000; // 150 ms - -// Tap drag gesture delay time. -// The time between up and the next up must be greater than this to be considered a -// drag. Otherwise, the previous tap is finished and a new tap begins. -static const nsecs_t TAP_DRAG_INTERVAL = 150 * 1000000; // 150 ms - -// The distance in pixels that the pointer is allowed to move from initial down -// to up and still be called a tap. -static const float TAP_SLOP = 10.0f; // 10 pixels - -// Time after the first touch points go down to settle on an initial centroid. -// This is intended to be enough time to handle cases where the user puts down two -// fingers at almost but not quite exactly the same time. -static const nsecs_t MULTITOUCH_SETTLE_INTERVAL = 100 * 1000000; // 100ms - -// The transition from PRESS to SWIPE or FREEFORM gesture mode is made when -// both of the pointers are moving at least this fast. -static const float MULTITOUCH_MIN_SPEED = 150.0f; // pixels per second - -// The transition from PRESS to SWIPE gesture mode can only occur when the -// cosine of the angle between the two vectors is greater than or equal to than this value -// which indicates that the vectors are oriented in the same direction. -// When the vectors are oriented in the exactly same direction, the cosine is 1.0. -// (In exactly opposite directions, the cosine is -1.0.) -static const float SWIPE_TRANSITION_ANGLE_COSINE = 0.5f; // cosine of 45 degrees - -// The transition from PRESS to SWIPE gesture mode can only occur when the -// fingers are no more than this far apart relative to the diagonal size of -// the touch pad. For example, a ratio of 0.5 means that the fingers must be -// no more than half the diagonal size of the touch pad apart. -static const float SWIPE_MAX_WIDTH_RATIO = 0.333f; // 1/3 - -// The gesture movement speed factor relative to the size of the display. -// Movement speed applies when the fingers are moving in the same direction. -// Without acceleration, a full swipe of the touch pad diagonal in movement mode -// will cover this portion of the display diagonal. -static const float GESTURE_MOVEMENT_SPEED_RATIO = 0.8f; - -// The gesture zoom speed factor relative to the size of the display. -// Zoom speed applies when the fingers are mostly moving relative to each other -// to execute a scale gesture or similar. -// Without acceleration, a full swipe of the touch pad diagonal in zoom mode -// will cover this portion of the display diagonal. -static const float GESTURE_ZOOM_SPEED_RATIO = 0.3f; - - // --- Static Functions --- template<typename T> @@ -281,6 +220,8 @@ InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputDispatcherInterface>& dispatcher) : mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher), mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX) { + mPolicy->getReaderConfiguration(&mConfig); + configureExcludedDevices(); updateGlobalMetaState(); updateInputConfiguration(); @@ -514,11 +455,8 @@ void InputReader::handleConfigurationChanged(nsecs_t when) { } void InputReader::configureExcludedDevices() { - Vector<String8> excludedDeviceNames; - mPolicy->getExcludedDeviceNames(excludedDeviceNames); - - for (size_t i = 0; i < excludedDeviceNames.size(); i++) { - mEventHub->addExcludedDevice(excludedDeviceNames[i]); + for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { + mEventHub->addExcludedDevice(mConfig.excludedDeviceNames[i]); } } @@ -752,6 +690,46 @@ void InputReader::dump(String8& dump) { mDevices.valueAt(i)->dump(dump); } } // release device registy reader lock + + dump.append(INDENT "Configuration:\n"); + dump.append(INDENT2 "ExcludedDeviceNames: ["); + for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { + if (i != 0) { + dump.append(", "); + } + dump.append(mConfig.excludedDeviceNames.itemAt(i).string()); + } + dump.append("]\n"); + dump.appendFormat(INDENT2 "FilterTouchEvents: %s\n", + toString(mConfig.filterTouchEvents)); + dump.appendFormat(INDENT2 "FilterJumpyTouchEvents: %s\n", + toString(mConfig.filterJumpyTouchEvents)); + dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", + mConfig.virtualKeyQuietTime * 0.000001f); + + dump.appendFormat(INDENT2 "PointerGesture:\n"); + dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", + mConfig.pointerGestureQuietInterval * 0.000001f); + dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", + mConfig.pointerGestureDragMinSwitchSpeed); + dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n", + mConfig.pointerGestureTapInterval * 0.000001f); + dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n", + mConfig.pointerGestureTapDragInterval * 0.000001f); + dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n", + mConfig.pointerGestureTapSlop); + dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n", + mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); + dump.appendFormat(INDENT3 "MultitouchMinSpeed: %0.1fpx/s\n", + mConfig.pointerGestureMultitouchMinSpeed); + dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", + mConfig.pointerGestureSwipeTransitionAngleCosine); + dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", + mConfig.pointerGestureSwipeMaxWidthRatio); + dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n", + mConfig.pointerGestureMovementSpeedRatio); + dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n", + mConfig.pointerGestureZoomSpeedRatio); } @@ -1696,6 +1674,8 @@ void CursorInputMapper::fadePointer() { TouchInputMapper::TouchInputMapper(InputDevice* device) : InputMapper(device) { + mConfig = getConfig(); + mLocked.surfaceOrientation = -1; mLocked.surfaceWidth = -1; mLocked.surfaceHeight = -1; @@ -1868,10 +1848,9 @@ void TouchInputMapper::configure() { } void TouchInputMapper::configureParameters() { - mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); - mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime(); + mParameters.useBadTouchFilter = mConfig->filterTouchEvents; + mParameters.useAveragingTouchFilter = mConfig->filterTouchEvents; + mParameters.useJumpyTouchFilter = mConfig->filterJumpyTouchEvents; // TODO: select the default gesture mode based on whether the device supports // distinct multitouch @@ -2265,21 +2244,22 @@ bool TouchInputMapper::configureSurfaceLocked() { // X and Y of the same number of raw units cover the same physical distance. const float scaleFactor = 0.8f; - mLocked.pointerGestureXMovementScale = GESTURE_MOVEMENT_SPEED_RATIO + mLocked.pointerGestureXMovementScale = mConfig->pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; mLocked.pointerGestureYMovementScale = mLocked.pointerGestureXMovementScale; // Scale zooms to cover a smaller range of the display than movements do. // This value determines the area around the pointer that is affected by freeform // pointer gestures. - mLocked.pointerGestureXZoomScale = GESTURE_ZOOM_SPEED_RATIO + mLocked.pointerGestureXZoomScale = mConfig->pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; mLocked.pointerGestureYZoomScale = mLocked.pointerGestureXZoomScale; // Max width between pointers to detect a swipe gesture is more than some fraction // of the diagonal axis of the touch pad. Touches that are wider than this are // translated into freeform gestures. - mLocked.pointerGestureMaxSwipeWidth = SWIPE_MAX_WIDTH_RATIO * rawDiagonal; + mLocked.pointerGestureMaxSwipeWidth = + mConfig->pointerGestureSwipeMaxWidthRatio * rawDiagonal; // Reset the current pointer gesture. mPointerGesture.reset(); @@ -2945,8 +2925,8 @@ void TouchInputMapper::suppressSwipeOntoVirtualKeys(nsecs_t when) { // area and accidentally triggers a virtual key. This often happens when virtual keys // are layed out below the screen near to where the on screen keyboard's space bar // is displayed. - if (mParameters.virtualKeyQuietTime > 0 && mCurrentTouch.pointerCount != 0) { - mContext->disableVirtualKeysUntil(when + mParameters.virtualKeyQuietTime); + if (mConfig->virtualKeyQuietTime > 0 && mCurrentTouch.pointerCount != 0) { + mContext->disableVirtualKeysUntil(when + mConfig->virtualKeyQuietTime); } } @@ -3260,12 +3240,6 @@ void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags, void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) { - // Switch pointer presentation. - mPointerController->setPresentation( - mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS - ? PointerControllerInterface::PRESENTATION_SPOT - : PointerControllerInterface::PRESENTATION_POINTER); - // Update current gesture coordinates. bool cancelPreviousGesture, finishPreviousGesture; bool sendEvents = preparePointerGestures(when, @@ -3274,6 +3248,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag return; } + // Switch pointer presentation. + mPointerController->setPresentation( + mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS + ? PointerControllerInterface::PRESENTATION_SPOT + : PointerControllerInterface::PRESENTATION_POINTER); + // Show or hide the pointer if needed. switch (mPointerGesture.currentGestureMode) { case PointerGesture::NEUTRAL: @@ -3441,9 +3421,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, #endif if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL) { + if (when <= mPointerGesture.tapUpTime + mConfig->pointerGestureTapDragInterval) { // The tap/drag timeout has not yet expired. - getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL); + getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + + mConfig->pointerGestureTapDragInterval); } else { // The tap is finished. #if DEBUG_GESTURES @@ -3512,7 +3493,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if (activeTouchId < 0) { mPointerGesture.resetQuietTime(); } else { - isQuietTime = when < mPointerGesture.quietTime + QUIET_INTERVAL; + isQuietTime = when < mPointerGesture.quietTime + mConfig->pointerGestureQuietInterval; if (!isQuietTime) { if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS || mPointerGesture.lastGestureMode == PointerGesture::SWIPE @@ -3583,7 +3564,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if (activeTouchId >= 0) { if (mCurrentTouch.pointerCount > 1) { int32_t bestId = -1; - float bestSpeed = DRAG_MIN_SWITCH_SPEED; + float bestSpeed = mConfig->pointerGestureDragMinSwitchSpeed; for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) { uint32_t id = mCurrentTouch.pointers[i].id; float vx, vy; @@ -3661,21 +3642,23 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, *outFinishPreviousGesture = true; // Watch for taps coming out of HOVER or TAP_DRAG mode. + // Checking for taps after TAP_DRAG allows us to detect double-taps. bool tapped = false; if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) && mLastTouch.pointerCount == 1) { - if (when <= mPointerGesture.tapDownTime + TAP_INTERVAL) { + if (when <= mPointerGesture.tapDownTime + mConfig->pointerGestureTapInterval) { float x, y; mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= TAP_SLOP - && fabs(y - mPointerGesture.tapY) <= TAP_SLOP) { + if (fabs(x - mPointerGesture.tapX) <= mConfig->pointerGestureTapSlop + && fabs(y - mPointerGesture.tapY) <= mConfig->pointerGestureTapSlop) { #if DEBUG_GESTURES LOGD("Gestures: TAP"); #endif mPointerGesture.tapUpTime = when; - getContext()->requestTimeoutAtTime(when + TAP_DRAG_INTERVAL); + getContext()->requestTimeoutAtTime(when + + mConfig->pointerGestureTapDragInterval); mPointerGesture.activeGestureId = 0; mPointerGesture.currentGestureMode = PointerGesture::TAP; @@ -3740,11 +3723,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + TAP_DRAG_INTERVAL) { + if (when <= mPointerGesture.tapUpTime + mConfig->pointerGestureTapDragInterval) { float x, y; mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= TAP_SLOP - && fabs(y - mPointerGesture.tapY) <= TAP_SLOP) { + if (fabs(x - mPointerGesture.tapX) <= mConfig->pointerGestureTapSlop + && fabs(y - mPointerGesture.tapY) <= mConfig->pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } else { #if DEBUG_GESTURES @@ -3838,7 +3821,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, LOG_ASSERT(activeTouchId >= 0); bool needReference = false; - bool settled = when >= mPointerGesture.firstTouchTime + MULTITOUCH_SETTLE_INTERVAL; + bool settled = when >= mPointerGesture.firstTouchTime + + mConfig->pointerGestureMultitouchSettleInterval; if (mPointerGesture.lastGestureMode != PointerGesture::PRESS && mPointerGesture.lastGestureMode != PointerGesture::SWIPE && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { @@ -3932,14 +3916,15 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, float speed1 = hypotf(vx1, vy1); float speed2 = hypotf(vx2, vy2); - if (speed1 >= MULTITOUCH_MIN_SPEED && speed2 >= MULTITOUCH_MIN_SPEED) { + if (speed1 >= mConfig->pointerGestureMultitouchMinSpeed + && speed2 >= mConfig->pointerGestureMultitouchMinSpeed) { // Calculate the dot product of the velocity vectors. // When the vectors are oriented in approximately the same direction, // the angle betweeen them is near zero and the cosine of the angle // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). float dot = vx1 * vx2 + vy1 * vy2; float cosine = dot / (speed1 * speed2); // denominator always > 0 - if (cosine >= SWIPE_TRANSITION_ANGLE_COSINE) { + if (cosine >= mConfig->pointerGestureSwipeTransitionAngleCosine) { // Pointers are moving in the same direction. Switch to SWIPE. #if DEBUG_GESTURES LOGD("Gestures: PRESS transitioned to SWIPE, " diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 0fbc93c..db4679b 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -40,6 +40,109 @@ class InputMapper; /* + * Input reader configuration. + * + * Specifies various options that modify the behavior of the input reader. + */ +struct InputReaderConfiguration { + // Determines whether to turn on some hacks we have to improve the touch interaction with a + // certain device whose screen currently is not all that good. + bool filterTouchEvents; + + // Determines whether to turn on some hacks to improve touch interaction with another device + // where touch coordinate data can get corrupted. + bool filterJumpyTouchEvents; + + // Gets the amount of time to disable virtual keys after the screen is touched + // in order to filter out accidental virtual key presses due to swiping gestures + // or taps near the edge of the display. May be 0 to disable the feature. + nsecs_t virtualKeyQuietTime; + + // The excluded device names for the platform. + // Devices with these names will be ignored. + Vector<String8> excludedDeviceNames; + + // Quiet time between certain pointer gesture transitions. + // Time to allow for all fingers or buttons to settle into a stable state before + // starting a new gesture. + nsecs_t pointerGestureQuietInterval; + + // The minimum speed that a pointer must travel for us to consider switching the active + // touch pointer to it during a drag. This threshold is set to avoid switching due + // to noise from a finger resting on the touch pad (perhaps just pressing it down). + float pointerGestureDragMinSwitchSpeed; // in pixels per second + + // Tap gesture delay time. + // The time between down and up must be less than this to be considered a tap. + nsecs_t pointerGestureTapInterval; + + // Tap drag gesture delay time. + // The time between the previous tap's up and the next down must be less than + // this to be considered a drag. Otherwise, the previous tap is finished and a + // new tap begins. + // + // Note that the previous tap will be held down for this entire duration so this + // interval must be shorter than the long press timeout. + nsecs_t pointerGestureTapDragInterval; + + // The distance in pixels that the pointer is allowed to move from initial down + // to up and still be called a tap. + float pointerGestureTapSlop; // in pixels + + // Time after the first touch points go down to settle on an initial centroid. + // This is intended to be enough time to handle cases where the user puts down two + // fingers at almost but not quite exactly the same time. + nsecs_t pointerGestureMultitouchSettleInterval; + + // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when + // both of the pointers are moving at least this fast. + float pointerGestureMultitouchMinSpeed; // in pixels per second + + // The transition from PRESS to SWIPE gesture mode can only occur when the + // cosine of the angle between the two vectors is greater than or equal to than this value + // which indicates that the vectors are oriented in the same direction. + // When the vectors are oriented in the exactly same direction, the cosine is 1.0. + // (In exactly opposite directions, the cosine is -1.0.) + float pointerGestureSwipeTransitionAngleCosine; + + // The transition from PRESS to SWIPE gesture mode can only occur when the + // fingers are no more than this far apart relative to the diagonal size of + // the touch pad. For example, a ratio of 0.5 means that the fingers must be + // no more than half the diagonal size of the touch pad apart. + float pointerGestureSwipeMaxWidthRatio; + + // The gesture movement speed factor relative to the size of the display. + // Movement speed applies when the fingers are moving in the same direction. + // Without acceleration, a full swipe of the touch pad diagonal in movement mode + // will cover this portion of the display diagonal. + float pointerGestureMovementSpeedRatio; + + // The gesture zoom speed factor relative to the size of the display. + // Zoom speed applies when the fingers are mostly moving relative to each other + // to execute a scale gesture or similar. + // Without acceleration, a full swipe of the touch pad diagonal in zoom mode + // will cover this portion of the display diagonal. + float pointerGestureZoomSpeedRatio; + + InputReaderConfiguration() : + filterTouchEvents(false), + filterJumpyTouchEvents(false), + virtualKeyQuietTime(0), + pointerGestureQuietInterval(100 * 1000000LL), // 100 ms + pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second + pointerGestureTapInterval(150 * 1000000LL), // 150 ms + pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms + pointerGestureTapSlop(10.0f), // 10 pixels + pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms + pointerGestureMultitouchMinSpeed(150.0f), // 150 pixels per second + pointerGestureSwipeTransitionAngleCosine(0.5f), // cosine of 45degrees + pointerGestureSwipeMaxWidthRatio(0.333f), + pointerGestureMovementSpeedRatio(0.8f), + pointerGestureZoomSpeedRatio(0.3f) { } +}; + + +/* * Input reader policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager @@ -68,24 +171,8 @@ public: virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation) = 0; - /* Determines whether to turn on some hacks we have to improve the touch interaction with a - * certain device whose screen currently is not all that good. - */ - virtual bool filterTouchEvents() = 0; - - /* Determines whether to turn on some hacks to improve touch interaction with another device - * where touch coordinate data can get corrupted. - */ - virtual bool filterJumpyTouchEvents() = 0; - - /* Gets the amount of time to disable virtual keys after the screen is touched - * in order to filter out accidental virtual key presses due to swiping gestures - * or taps near the edge of the display. May be 0 to disable the feature. - */ - virtual nsecs_t getVirtualKeyQuietTime() = 0; - - /* Gets the excluded device names for the platform. */ - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0; + /* Gets the input reader configuration. */ + virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0; @@ -162,6 +249,7 @@ public: virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual InputReaderPolicyInterface* getPolicy() = 0; + virtual const InputReaderConfiguration* getConfig() = 0; virtual InputDispatcherInterface* getDispatcher() = 0; virtual EventHubInterface* getEventHub() = 0; }; @@ -212,7 +300,10 @@ private: sp<InputReaderPolicyInterface> mPolicy; sp<InputDispatcherInterface> mDispatcher; + InputReaderConfiguration mConfig; + virtual InputReaderPolicyInterface* getPolicy() { return mPolicy.get(); } + virtual const InputReaderConfiguration* getConfig() { return &mConfig; } virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); } virtual EventHubInterface* getEventHub() { return mEventHub.get(); } @@ -353,6 +444,7 @@ public: inline const String8 getDeviceName() { return mDevice->getName(); } inline InputReaderContext* getContext() { return mContext; } inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } + inline const InputReaderConfiguration* getConfig() { return mContext->getConfig(); } inline InputDispatcherInterface* getDispatcher() { return mContext->getDispatcher(); } inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } @@ -665,6 +757,9 @@ protected: uint32_t mTouchSource; // sources when reporting touch data uint32_t mPointerSource; // sources when reporting pointer gestures + // The reader's configuration. + const InputReaderConfiguration* mConfig; + // Immutable configuration parameters. struct Parameters { enum DeviceType { @@ -680,7 +775,6 @@ protected: bool useBadTouchFilter; bool useJumpyTouchFilter; bool useAveragingTouchFilter; - nsecs_t virtualKeyQuietTime; enum GestureMode { GESTURE_MODE_POINTER, @@ -939,6 +1033,8 @@ private: // Exactly one finger dragging following a tap. // Pointer follows the active finger. // Emits DOWN, MOVE and UP events at the pointer location. + // + // Detect double-taps when the finger goes up while in TAP_DRAG mode. TAP_DRAG, // Button is pressed. @@ -949,6 +1045,8 @@ private: // Exactly one finger, button is not pressed. // Pointer follows the active finger. // Emits HOVER_MOVE events at the pointer location. + // + // Detect taps when the finger goes up while in HOVER mode. HOVER, // Exactly two fingers but neither have moved enough to clearly indicate diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp index 2f846c4..0a29bc6 100644 --- a/services/input/tests/InputDispatcher_test.cpp +++ b/services/input/tests/InputDispatcher_test.cpp @@ -35,6 +35,8 @@ static const int32_t INJECTOR_UID = 1001; // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { + InputDispatcherConfiguration mConfig; + protected: virtual ~FakeInputDispatcherPolicy() { } @@ -55,16 +57,12 @@ private: virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { } - virtual nsecs_t getKeyRepeatTimeout() { - return 500 * 1000000LL; - } - - virtual nsecs_t getKeyRepeatDelay() { - return 50 * 1000000LL; + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { + *outConfig = mConfig; } - virtual int32_t getMaxEventsPerSecond() { - return 60; + virtual bool isKeyRepeatEnabled() { + return true; } virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 8b3e731..b5f603a 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -120,17 +120,14 @@ class FakeInputReaderPolicy : public InputReaderPolicyInterface { }; KeyedVector<int32_t, DisplayInfo> mDisplayInfos; - bool mFilterTouchEvents; - bool mFilterJumpyTouchEvents; - Vector<String8> mExcludedDeviceNames; + InputReaderConfiguration mConfig; KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers; protected: virtual ~FakeInputReaderPolicy() { } public: - FakeInputReaderPolicy() : - mFilterTouchEvents(false), mFilterJumpyTouchEvents(false) { + FakeInputReaderPolicy() { } void removeDisplayInfo(int32_t displayId) { @@ -148,11 +145,11 @@ public: } void setFilterTouchEvents(bool enabled) { - mFilterTouchEvents = enabled; + mConfig.filterTouchEvents = enabled; } void setFilterJumpyTouchEvents(bool enabled) { - mFilterJumpyTouchEvents = enabled; + mConfig.filterJumpyTouchEvents = enabled; } virtual nsecs_t getVirtualKeyQuietTime() { @@ -160,7 +157,7 @@ public: } void addExcludedDeviceName(const String8& deviceName) { - mExcludedDeviceNames.push(deviceName); + mConfig.excludedDeviceNames.push(deviceName); } void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) { @@ -187,16 +184,8 @@ private: return false; } - virtual bool filterTouchEvents() { - return mFilterTouchEvents; - } - - virtual bool filterJumpyTouchEvents() { - return mFilterJumpyTouchEvents; - } - - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { - outExcludedDeviceNames.appendVector(mExcludedDeviceNames); + virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) { + *outConfig = mConfig; } virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) { @@ -739,6 +728,8 @@ class FakeInputReaderContext : public InputReaderContext { int32_t mGlobalMetaState; bool mUpdateGlobalMetaStateWasCalled; + InputReaderConfiguration mConfig; + public: FakeInputReaderContext(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, @@ -776,6 +767,11 @@ private: return mPolicy.get(); } + virtual const InputReaderConfiguration* getConfig() { + mPolicy->getReaderConfiguration(&mConfig); + return &mConfig; + } + virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); } diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java index becd44a..ab781f4 100644 --- a/services/java/com/android/server/wm/InputManager.java +++ b/services/java/com/android/server/wm/InputManager.java @@ -496,6 +496,26 @@ public class InputManager { } @SuppressWarnings("unused") + public int getTapTimeout() { + return ViewConfiguration.getTapTimeout(); + } + + @SuppressWarnings("unused") + public int getDoubleTapTimeout() { + return ViewConfiguration.getDoubleTapTimeout(); + } + + @SuppressWarnings("unused") + public int getLongPressTimeout() { + return ViewConfiguration.getLongPressTimeout(); + } + + @SuppressWarnings("unused") + public int getTouchSlop() { + return ViewConfiguration.get(mContext).getScaledTouchSlop(); + } + + @SuppressWarnings("unused") public int getMaxEventsPerSecond() { int result = 0; try { diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index dde4776..fef41c9 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -72,6 +72,10 @@ static struct { jmethodID getKeyRepeatTimeout; jmethodID getKeyRepeatDelay; jmethodID getMaxEventsPerSecond; + jmethodID getTapTimeout; + jmethodID getDoubleTapTimeout; + jmethodID getLongPressTimeout; + jmethodID getTouchSlop; jmethodID getPointerLayer; jmethodID getPointerIcon; } gCallbacksClassInfo; @@ -107,6 +111,16 @@ static struct { // --- Global functions --- +template<typename T> +inline static T min(const T& a, const T& b) { + return a < b ? a : b; +} + +template<typename T> +inline static T max(const T& a, const T& b) { + return a > b ? a : b; +} + static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env, const sp<InputApplicationHandle>& inputApplicationHandle) { if (inputApplicationHandle == NULL) { @@ -170,10 +184,7 @@ public: virtual bool getDisplayInfo(int32_t displayId, int32_t* width, int32_t* height, int32_t* orientation); - virtual bool filterTouchEvents(); - virtual bool filterJumpyTouchEvents(); - virtual nsecs_t getVirtualKeyQuietTime(); - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames); + virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -184,9 +195,8 @@ public: virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<InputWindowHandle>& inputWindowHandle); virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle); - virtual nsecs_t getKeyRepeatTimeout(); - virtual nsecs_t getKeyRepeatDelay(); - virtual int32_t getMaxEventsPerSecond(); + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig); + virtual bool isKeyRepeatEnabled(); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags); virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, @@ -208,18 +218,6 @@ private: jobject mCallbacksObj; sp<Looper> mLooper; - // Cached filtering policies. - int32_t mFilterTouchEvents; - int32_t mFilterJumpyTouchEvents; - nsecs_t mVirtualKeyQuietTime; - - // Cached key repeat policy. - nsecs_t mKeyRepeatTimeout; - nsecs_t mKeyRepeatDelay; - - // Cached throttling policy. - int32_t mMaxEventsPerSecond; - Mutex mLock; struct Locked { // Display size information. @@ -255,10 +253,7 @@ private: NativeInputManager::NativeInputManager(jobject contextObj, jobject callbacksObj, const sp<Looper>& looper) : - mLooper(looper), - mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1), - mKeyRepeatTimeout(-1), mKeyRepeatDelay(-1), - mMaxEventsPerSecond(-1) { + mLooper(looper) { JNIEnv* env = jniEnv(); mContextObj = env->NewGlobalRef(contextObj); @@ -371,73 +366,68 @@ bool NativeInputManager::getDisplayInfo(int32_t displayId, return result; } -bool NativeInputManager::filterTouchEvents() { - if (mFilterTouchEvents < 0) { - JNIEnv* env = jniEnv(); - - jboolean result = env->CallBooleanMethod(mCallbacksObj, - gCallbacksClassInfo.filterTouchEvents); - if (checkAndClearExceptionFromCallback(env, "filterTouchEvents")) { - result = false; - } +void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) { + JNIEnv* env = jniEnv(); - mFilterTouchEvents = result ? 1 : 0; + jboolean filterTouchEvents = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.filterTouchEvents); + if (!checkAndClearExceptionFromCallback(env, "filterTouchEvents")) { + outConfig->filterTouchEvents = filterTouchEvents; } - return mFilterTouchEvents; -} - -bool NativeInputManager::filterJumpyTouchEvents() { - if (mFilterJumpyTouchEvents < 0) { - JNIEnv* env = jniEnv(); - - jboolean result = env->CallBooleanMethod(mCallbacksObj, - gCallbacksClassInfo.filterJumpyTouchEvents); - if (checkAndClearExceptionFromCallback(env, "filterJumpyTouchEvents")) { - result = false; - } - mFilterJumpyTouchEvents = result ? 1 : 0; + jboolean filterJumpyTouchEvents = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.filterJumpyTouchEvents); + if (!checkAndClearExceptionFromCallback(env, "filterJumpyTouchEvents")) { + outConfig->filterJumpyTouchEvents = filterJumpyTouchEvents; } - return mFilterJumpyTouchEvents; -} -nsecs_t NativeInputManager::getVirtualKeyQuietTime() { - if (mVirtualKeyQuietTime < 0) { - JNIEnv* env = jniEnv(); - - jint result = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.getVirtualKeyQuietTimeMillis); - if (checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) { - result = 0; - } - if (result < 0) { - result = 0; - } - - mVirtualKeyQuietTime = milliseconds_to_nanoseconds(result); + jint virtualKeyQuietTime = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getVirtualKeyQuietTimeMillis); + if (!checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) { + outConfig->virtualKeyQuietTime = milliseconds_to_nanoseconds(virtualKeyQuietTime); } - return mVirtualKeyQuietTime; -} - -void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { - outExcludedDeviceNames.clear(); - - JNIEnv* env = jniEnv(); - jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj, + outConfig->excludedDeviceNames.clear(); + jobjectArray excludedDeviceNames = jobjectArray(env->CallObjectMethod(mCallbacksObj, gCallbacksClassInfo.getExcludedDeviceNames)); - if (! checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && result) { - jsize length = env->GetArrayLength(result); + if (!checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && excludedDeviceNames) { + jsize length = env->GetArrayLength(excludedDeviceNames); for (jsize i = 0; i < length; i++) { - jstring item = jstring(env->GetObjectArrayElement(result, i)); - + jstring item = jstring(env->GetObjectArrayElement(excludedDeviceNames, i)); const char* deviceNameChars = env->GetStringUTFChars(item, NULL); - outExcludedDeviceNames.add(String8(deviceNameChars)); + outConfig->excludedDeviceNames.add(String8(deviceNameChars)); env->ReleaseStringUTFChars(item, deviceNameChars); - env->DeleteLocalRef(item); } - env->DeleteLocalRef(result); + env->DeleteLocalRef(excludedDeviceNames); + } + + jint tapTimeout = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getTapTimeout); + if (!checkAndClearExceptionFromCallback(env, "getTapTimeout")) { + jint doubleTapTimeout = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getDoubleTapTimeout); + if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) { + jint longPressTimeout = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getLongPressTimeout); + if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) { + outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(tapTimeout); + + // We must ensure that the tap-drag interval is significantly shorter than + // the long-press timeout because the tap is held down for the entire duration + // of the double-tap timeout. + jint tapDragInterval = max(min(longPressTimeout - 100, + doubleTapTimeout), tapTimeout); + outConfig->pointerGestureTapDragInterval = + milliseconds_to_nanoseconds(tapDragInterval); + } + } + } + + jint touchSlop = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getTouchSlop); + if (!checkAndClearExceptionFromCallback(env, "getTouchSlop")) { + outConfig->pointerGestureTapSlop = touchSlop; } } @@ -559,54 +549,31 @@ void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& i } } -nsecs_t NativeInputManager::getKeyRepeatTimeout() { - if (! isScreenOn()) { - // Disable key repeat when the screen is off. - return -1; - } else { - if (mKeyRepeatTimeout < 0) { - JNIEnv* env = jniEnv(); - - jint result = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.getKeyRepeatTimeout); - if (checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) { - result = 500; - } +void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { + JNIEnv* env = jniEnv(); - mKeyRepeatTimeout = milliseconds_to_nanoseconds(result); - } - return mKeyRepeatTimeout; + jint keyRepeatTimeout = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getKeyRepeatTimeout); + if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) { + outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout); } -} -nsecs_t NativeInputManager::getKeyRepeatDelay() { - if (mKeyRepeatDelay < 0) { - JNIEnv* env = jniEnv(); - - jint result = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.getKeyRepeatDelay); - if (checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) { - result = 50; - } + jint keyRepeatDelay = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getKeyRepeatDelay); + if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) { + outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay); + } - mKeyRepeatDelay = milliseconds_to_nanoseconds(result); + jint maxEventsPerSecond = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.getMaxEventsPerSecond); + if (!checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) { + outConfig->maxEventsPerSecond = maxEventsPerSecond; } - return mKeyRepeatDelay; } -int32_t NativeInputManager::getMaxEventsPerSecond() { - if (mMaxEventsPerSecond < 0) { - JNIEnv* env = jniEnv(); - - jint result = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.getMaxEventsPerSecond); - if (checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) { - result = 60; - } - - mMaxEventsPerSecond = result; - } - return mMaxEventsPerSecond; +bool NativeInputManager::isKeyRepeatEnabled() { + // Only enable automatic key repeating when the screen is on. + return isScreenOn(); } void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) { @@ -1342,6 +1309,18 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, gCallbacksClassInfo.clazz, "getKeyRepeatDelay", "()I"); + GET_METHOD_ID(gCallbacksClassInfo.getTapTimeout, gCallbacksClassInfo.clazz, + "getTapTimeout", "()I"); + + GET_METHOD_ID(gCallbacksClassInfo.getDoubleTapTimeout, gCallbacksClassInfo.clazz, + "getDoubleTapTimeout", "()I"); + + GET_METHOD_ID(gCallbacksClassInfo.getLongPressTimeout, gCallbacksClassInfo.clazz, + "getLongPressTimeout", "()I"); + + GET_METHOD_ID(gCallbacksClassInfo.getTouchSlop, gCallbacksClassInfo.clazz, + "getTouchSlop", "()I"); + GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz, "getMaxEventsPerSecond", "()I"); |