From 05dc66ada6b61a6bdf806ffaa62617ac5394695d Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Wed, 2 Mar 2011 14:41:58 -0800 Subject: Fade out the mouse pointer after inactivity or other events. Fades out the mouse pointer: - after 15 seconds of inactivity normally - after 3 seconds of inactivity in lights out mode - after a non-modifier key down - after a touch down Extended the native Looper to support enqueuing time delayed messages. This is used by the PointerController to control pointer fade timing. Change-Id: I87792fea7dbe2d9376c78cf354fe3189a484d9da --- services/input/InputReader.cpp | 44 ++++++++++- services/input/InputReader.h | 10 +++ services/input/PointerController.cpp | 118 +++++++++++++++++++++++++++++- services/input/PointerController.h | 39 +++++++++- services/input/tests/InputReader_test.cpp | 12 +++ 5 files changed, 214 insertions(+), 9 deletions(-) (limited to 'services/input') diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index a865d9f..c3c143c 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -399,6 +399,17 @@ bool InputReader::shouldDropVirtualKey(nsecs_t now, } } +void InputReader::fadePointer() { + { // acquire device registry reader lock + RWLock::AutoRLock _rl(mDeviceRegistryLock); + + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->fadePointer(); + } + } // release device registry reader lock +} + void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) { { // acquire state lock AutoMutex _l(mStateLock); @@ -695,6 +706,14 @@ int32_t InputDevice::getMetaState() { return result; } +void InputDevice::fadePointer() { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->fadePointer(); + } +} + // --- InputMapper --- @@ -739,6 +758,9 @@ int32_t InputMapper::getMetaState() { return 0; } +void InputMapper::fadePointer() { +} + void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name) { if (axis.valid) { @@ -967,6 +989,10 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, getContext()->updateGlobalMetaState(); } + if (down && !isMetaKey(keyCode)) { + getContext()->fadePointer(); + } + if (policyFlags & POLICY_FLAG_FUNCTION) { newMetaState |= AMETA_FUNCTION_ON; } @@ -1348,6 +1374,9 @@ void CursorInputMapper::sync(nsecs_t when) { } else { hscroll = 0; } + if (hscroll != 0 || vscroll != 0) { + mPointerController->unfade(); + } } // release lock int32_t metaState = mContext->getGlobalMetaState(); @@ -1376,6 +1405,13 @@ int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCod } } +void CursorInputMapper::fadePointer() { + { // acquire lock + AutoMutex _l(mLock); + mPointerController->fade(); + } // release lock +} + // --- TouchInputMapper --- @@ -2275,7 +2311,6 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { uint32_t policyFlags = 0; // Preprocess pointer data. - if (mParameters.useBadTouchFilter) { if (applyBadTouchFilter()) { havePointerIds = false; @@ -2303,8 +2338,12 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { savedTouch = & mCurrentTouch; } - // Process touches and virtual keys. + // Hide the pointer on an initial down. + if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) { + getContext()->fadePointer(); + } + // Process touches and virtual keys. TouchResult touchResult = consumeOffScreenTouches(when, policyFlags); if (touchResult == DISPATCH_TOUCH) { detectGestures(when); @@ -2312,7 +2351,6 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { } // Copy current touch to last touch in preparation for the next cycle. - if (touchResult == DROP_STROKE) { mLastTouch.clear(); } else { diff --git a/services/input/InputReader.h b/services/input/InputReader.h index cf41535..b344ffe 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -157,6 +157,8 @@ public: virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode) = 0; + virtual void fadePointer() = 0; + virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputDispatcherInterface* getDispatcher() = 0; virtual EventHubInterface* getEventHub() = 0; @@ -241,6 +243,8 @@ private: virtual void updateGlobalMetaState(); virtual int32_t getGlobalMetaState(); + virtual void fadePointer(); + InputConfiguration mInputConfiguration; void updateInputConfiguration(); @@ -299,6 +303,8 @@ public: int32_t getMetaState(); + void fadePointer(); + inline const PropertyMap& getConfiguration() { return mConfiguration; } @@ -351,6 +357,8 @@ public: virtual int32_t getMetaState(); + virtual void fadePointer(); + protected: InputDevice* mDevice; InputReaderContext* mContext; @@ -459,6 +467,8 @@ public: virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual void fadePointer(); + private: // Amount that trackball needs to move in order to generate a key event. static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp index 92af51e..954872b 100644 --- a/services/input/PointerController.cpp +++ b/services/input/PointerController.cpp @@ -35,8 +35,22 @@ namespace android { // --- PointerController --- -PointerController::PointerController(int32_t pointerLayer) : - mPointerLayer(pointerLayer) { +// Time to wait before starting the fade when the pointer is inactive. +static const nsecs_t INACTIVITY_FADE_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds +static const nsecs_t INACTIVITY_FADE_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds + +// Time to spend fading out the pointer completely. +static const nsecs_t FADE_DURATION = 500 * 1000000LL; // 500 ms + +// Time to wait between frames. +static const nsecs_t FADE_FRAME_INTERVAL = 1000000000LL / 60; + +// Amount to subtract from alpha per frame. +static const float FADE_DECAY_PER_FRAME = float(FADE_FRAME_INTERVAL) / FADE_DURATION; + + +PointerController::PointerController(const sp& looper, int32_t pointerLayer) : + mLooper(looper), mPointerLayer(pointerLayer) { AutoMutex _l(mLock); mLocked.displayWidth = -1; @@ -51,12 +65,19 @@ PointerController::PointerController(int32_t pointerLayer) : mLocked.iconHotSpotX = 0; mLocked.iconHotSpotY = 0; + mLocked.fadeAlpha = 1; + mLocked.inactivityFadeDelay = INACTIVITY_FADE_DELAY_NORMAL; + mLocked.wantVisible = false; mLocked.visible = false; mLocked.drawn = false; + + mHandler = new WeakMessageHandler(this); } PointerController::~PointerController() { + mLooper->removeMessages(mHandler); + if (mSurfaceControl != NULL) { mSurfaceControl->clear(); mSurfaceControl.clear(); @@ -120,7 +141,7 @@ void PointerController::setButtonState(uint32_t buttonState) { if (mLocked.buttonState != buttonState) { mLocked.buttonState = buttonState; - mLocked.wantVisible = true; + unfadeBeforeUpdateLocked(); updateLocked(); } } @@ -157,7 +178,7 @@ void PointerController::setPositionLocked(float x, float y) { } else { mLocked.pointerY = y; } - mLocked.wantVisible = true; + unfadeBeforeUpdateLocked(); updateLocked(); } } @@ -169,6 +190,29 @@ void PointerController::getPosition(float* outX, float* outY) const { *outY = mLocked.pointerY; } +void PointerController::fade() { + AutoMutex _l(mLock); + + startFadeLocked(); +} + +void PointerController::unfade() { + AutoMutex _l(mLock); + + if (unfadeBeforeUpdateLocked()) { + updateLocked(); + } +} + +void PointerController::setInactivityFadeDelay(InactivityFadeDelay inactivityFadeDelay) { + AutoMutex _l(mLock); + + if (mLocked.inactivityFadeDelay != inactivityFadeDelay) { + mLocked.inactivityFadeDelay = inactivityFadeDelay; + startInactivityFadeDelayLocked(); + } +} + void PointerController::updateLocked() { bool wantVisibleAndHavePointerIcon = mLocked.wantVisible && mLocked.iconBitmap; @@ -201,6 +245,12 @@ void PointerController::updateLocked() { goto CloseTransaction; } + status = mSurfaceControl->setAlpha(mLocked.fadeAlpha); + if (status) { + LOGE("Error %d setting pointer surface alpha.", status); + goto CloseTransaction; + } + if (!mLocked.visible) { status = mSurfaceControl->setLayer(mPointerLayer); if (status) { @@ -412,4 +462,64 @@ bool PointerController::resizeSurfaceLocked(int32_t width, int32_t height) { return true; } +void PointerController::handleMessage(const Message& message) { + switch (message.what) { + case MSG_FADE_STEP: { + AutoMutex _l(mLock); + fadeStepLocked(); + break; + } + } +} + +bool PointerController::unfadeBeforeUpdateLocked() { + sendFadeStepMessageDelayedLocked(getInactivityFadeDelayTimeLocked()); + + if (isFadingLocked()) { + mLocked.wantVisible = true; + mLocked.fadeAlpha = 1; + return true; // update required to effect the unfade + } + return false; // update not required +} + +void PointerController::startFadeLocked() { + if (!isFadingLocked()) { + sendFadeStepMessageDelayedLocked(0); + } +} + +void PointerController::startInactivityFadeDelayLocked() { + if (!isFadingLocked()) { + sendFadeStepMessageDelayedLocked(getInactivityFadeDelayTimeLocked()); + } +} + +void PointerController::fadeStepLocked() { + if (mLocked.wantVisible) { + mLocked.fadeAlpha -= FADE_DECAY_PER_FRAME; + if (mLocked.fadeAlpha < 0) { + mLocked.fadeAlpha = 0; + mLocked.wantVisible = false; + } else { + sendFadeStepMessageDelayedLocked(FADE_FRAME_INTERVAL); + } + updateLocked(); + } +} + +bool PointerController::isFadingLocked() { + return !mLocked.wantVisible || mLocked.fadeAlpha != 1; +} + +nsecs_t PointerController::getInactivityFadeDelayTimeLocked() { + return mLocked.inactivityFadeDelay == INACTIVITY_FADE_DELAY_SHORT + ? INACTIVITY_FADE_DELAY_TIME_SHORT : INACTIVITY_FADE_DELAY_TIME_NORMAL; +} + +void PointerController::sendFadeStepMessageDelayedLocked(nsecs_t delayTime) { + mLooper->removeMessages(mHandler, MSG_FADE_STEP); + mLooper->sendMessageDelayed(delayTime, mHandler, Message(MSG_FADE_STEP)); +} + } // namespace android diff --git a/services/input/PointerController.h b/services/input/PointerController.h index a2a9955..e28dd7d 100644 --- a/services/input/PointerController.h +++ b/services/input/PointerController.h @@ -18,7 +18,9 @@ #define _UI_POINTER_CONTROLLER_H #include +#include #include +#include #include #include @@ -64,6 +66,12 @@ public: /* Gets the absolute location of the pointer. */ virtual void getPosition(float* outX, float* outY) const = 0; + + /* Fades the pointer out now. */ + virtual void fade() = 0; + + /* Makes the pointer visible if it has faded out. */ + virtual void unfade() = 0; }; @@ -72,12 +80,17 @@ public: * * Handles pointer acceleration and animation. */ -class PointerController : public PointerControllerInterface { +class PointerController : public PointerControllerInterface, public MessageHandler { protected: virtual ~PointerController(); public: - PointerController(int32_t pointerLayer); + enum InactivityFadeDelay { + INACTIVITY_FADE_DELAY_NORMAL = 0, + INACTIVITY_FADE_DELAY_SHORT = 1, + }; + + PointerController(const sp& looper, int32_t pointerLayer); virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; @@ -86,14 +99,22 @@ public: virtual uint32_t getButtonState() const; virtual void setPosition(float x, float y); virtual void getPosition(float* outX, float* outY) const; + virtual void fade(); + virtual void unfade(); void setDisplaySize(int32_t width, int32_t height); void setDisplayOrientation(int32_t orientation); void setPointerIcon(const SkBitmap* bitmap, float hotSpotX, float hotSpotY); + void setInactivityFadeDelay(InactivityFadeDelay inactivityFadeDelay); private: + enum { + MSG_FADE_STEP = 0, + }; + mutable Mutex mLock; + sp mLooper; int32_t mPointerLayer; sp mSurfaceComposerClient; sp mSurfaceControl; @@ -111,17 +132,31 @@ private: float iconHotSpotX; float iconHotSpotY; + float fadeAlpha; + InactivityFadeDelay inactivityFadeDelay; + bool wantVisible; bool visible; bool drawn; } mLocked; + sp mHandler; + bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; void setPositionLocked(float x, float y); void updateLocked(); bool createSurfaceIfNeededLocked(); bool drawPointerIfNeededLocked(); bool resizeSurfaceLocked(int32_t width, int32_t height); + + void handleMessage(const Message& message); + bool unfadeBeforeUpdateLocked(); + void startFadeLocked(); + void startInactivityFadeDelayLocked(); + void fadeStepLocked(); + bool isFadingLocked(); + nsecs_t getInactivityFadeDelayTimeLocked(); + void sendFadeStepMessageDelayedLocked(nsecs_t delayTime); }; } // namespace android diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index fac71bb..864241e 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -79,6 +79,12 @@ private: *outX = 0; *outY = 0; } + + virtual void fade() { + } + + virtual void unfade() { + } }; @@ -743,6 +749,9 @@ private: InputDevice* device, int32_t keyCode, int32_t scanCode) { return false; } + + virtual void fadePointer() { + } }; @@ -875,6 +884,9 @@ private: virtual int32_t getMetaState() { return mMetaState; } + + virtual void fadePointer() { + } }; -- cgit v1.1