diff options
| -rw-r--r-- | services/input/Android.mk | 4 | ||||
| -rw-r--r-- | services/input/InputReader.h | 4 | ||||
| -rw-r--r-- | services/input/PointerController.cpp | 212 | ||||
| -rw-r--r-- | services/input/PointerController.h | 26 | ||||
| -rw-r--r-- | services/input/SpotController.cpp | 45 | ||||
| -rw-r--r-- | services/input/SpotController.h | 71 | ||||
| -rw-r--r-- | services/input/SpriteController.cpp | 472 | ||||
| -rw-r--r-- | services/input/SpriteController.h | 251 | ||||
| -rw-r--r-- | services/input/tests/InputReader_test.cpp | 4 | ||||
| -rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 34 |
10 files changed, 904 insertions, 219 deletions
diff --git a/services/input/Android.mk b/services/input/Android.mk index d7b61fc..58b5318 100644 --- a/services/input/Android.mk +++ b/services/input/Android.mk @@ -22,7 +22,9 @@ LOCAL_SRC_FILES:= \ InputManager.cpp \ InputReader.cpp \ InputWindow.cpp \ - PointerController.cpp + PointerController.cpp \ + SpotController.cpp \ + SpriteController.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/services/input/InputReader.h b/services/input/InputReader.h index cf9b13d..9ed1391 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -20,6 +20,7 @@ #include "EventHub.h" #include "InputDispatcher.h" #include "PointerController.h" +#include "SpotController.h" #include <ui/Input.h> #include <ui/DisplayInfo.h> @@ -89,6 +90,9 @@ public: /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0; + + /* Gets a spot controller associated with the specified touch pad device. */ + virtual sp<SpotControllerInterface> obtainSpotController(int32_t deviceId) = 0; }; diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp index a4ee295..15effb7 100644 --- a/services/input/PointerController.cpp +++ b/services/input/PointerController.cpp @@ -49,8 +49,11 @@ static const nsecs_t FADE_FRAME_INTERVAL = 1000000000LL / 60; static const float FADE_DECAY_PER_FRAME = float(FADE_FRAME_INTERVAL) / FADE_DURATION; -PointerController::PointerController(const sp<Looper>& looper, int32_t pointerLayer) : - mLooper(looper), mPointerLayer(pointerLayer) { +PointerController::PointerController(const sp<Looper>& looper, + const sp<SpriteController>& spriteController) : + mLooper(looper), mSpriteController(spriteController) { + mHandler = new WeakMessageHandler(this); + AutoMutex _l(mLock); mLocked.displayWidth = -1; @@ -61,34 +64,20 @@ PointerController::PointerController(const sp<Looper>& looper, int32_t pointerLa mLocked.pointerY = 0; mLocked.buttonState = 0; - mLocked.iconBitmap = NULL; - 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); + mLocked.sprite = mSpriteController->createSprite(); } PointerController::~PointerController() { mLooper->removeMessages(mHandler); - if (mSurfaceControl != NULL) { - mSurfaceControl->clear(); - mSurfaceControl.clear(); - } - - if (mSurfaceComposerClient != NULL) { - mSurfaceComposerClient->dispose(); - mSurfaceComposerClient.clear(); - } + AutoMutex _l(mLock); - delete mLocked.iconBitmap; + mLocked.sprite.clear(); } bool PointerController::getBounds(float* outMinX, float* outMinY, @@ -214,75 +203,11 @@ void PointerController::setInactivityFadeDelay(InactivityFadeDelay inactivityFad } void PointerController::updateLocked() { - bool wantVisibleAndHavePointerIcon = mLocked.wantVisible && mLocked.iconBitmap; - - if (wantVisibleAndHavePointerIcon) { - // Want the pointer to be visible. - // Ensure the surface is created and drawn. - if (!createSurfaceIfNeededLocked() || !drawPointerIfNeededLocked()) { - return; - } - } else { - // Don't want the pointer to be visible. - // If it is not visible then we are done. - if (mSurfaceControl == NULL || !mLocked.visible) { - return; - } - } - - status_t status = mSurfaceComposerClient->openTransaction(); - if (status) { - LOGE("Error opening surface transaction to update pointer surface."); - return; - } - - if (wantVisibleAndHavePointerIcon) { - status = mSurfaceControl->setPosition( - mLocked.pointerX - mLocked.iconHotSpotX, - mLocked.pointerY - mLocked.iconHotSpotY); - if (status) { - LOGE("Error %d moving pointer surface.", status); - 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) { - LOGE("Error %d setting pointer surface layer.", status); - goto CloseTransaction; - } - - status = mSurfaceControl->show(mPointerLayer); - if (status) { - LOGE("Error %d showing pointer surface.", status); - goto CloseTransaction; - } - - mLocked.visible = true; - } - } else { - if (mLocked.visible) { - status = mSurfaceControl->hide(); - if (status) { - LOGE("Error %d hiding pointer surface.", status); - goto CloseTransaction; - } - - mLocked.visible = false; - } - } - -CloseTransaction: - status = mSurfaceComposerClient->closeTransaction(); - if (status) { - LOGE("Error closing surface transaction to update pointer surface."); - } + mLocked.sprite->openTransaction(); + mLocked.sprite->setPosition(mLocked.pointerX, mLocked.pointerY); + mLocked.sprite->setAlpha(mLocked.fadeAlpha); + mLocked.sprite->setVisible(mLocked.visible); + mLocked.sprite->closeTransaction(); } void PointerController::setDisplaySize(int32_t width, int32_t height) { @@ -339,7 +264,7 @@ void PointerController::setDisplayOrientation(int32_t orientation) { case DISPLAY_ORIENTATION_90: temp = x; x = y; - y = mLocked.displayWidth - x; + y = mLocked.displayWidth - temp; break; case DISPLAY_ORIENTATION_180: x = mLocked.displayWidth - x; @@ -365,106 +290,7 @@ void PointerController::setDisplayOrientation(int32_t orientation) { void PointerController::setPointerIcon(const SkBitmap* bitmap, float hotSpotX, float hotSpotY) { AutoMutex _l(mLock); - if (mLocked.iconBitmap) { - delete mLocked.iconBitmap; - mLocked.iconBitmap = NULL; - } - - if (bitmap) { - mLocked.iconBitmap = new SkBitmap(); - bitmap->copyTo(mLocked.iconBitmap, SkBitmap::kARGB_8888_Config); - } - - mLocked.iconHotSpotX = hotSpotX; - mLocked.iconHotSpotY = hotSpotY; - mLocked.drawn = false; -} - -bool PointerController::createSurfaceIfNeededLocked() { - if (!mLocked.iconBitmap) { - // If we don't have a pointer icon, then no point allocating a surface now. - return false; - } - - if (mSurfaceComposerClient == NULL) { - mSurfaceComposerClient = new SurfaceComposerClient(); - } - - if (mSurfaceControl == NULL) { - mSurfaceControl = mSurfaceComposerClient->createSurface(getpid(), - String8("Pointer Icon"), 0, - mLocked.iconBitmap->width(), mLocked.iconBitmap->height(), - PIXEL_FORMAT_RGBA_8888); - if (mSurfaceControl == NULL) { - LOGE("Error creating pointer surface."); - return false; - } - } - return true; -} - -bool PointerController::drawPointerIfNeededLocked() { - if (!mLocked.drawn) { - if (!mLocked.iconBitmap) { - return false; - } - - if (!resizeSurfaceLocked(mLocked.iconBitmap->width(), mLocked.iconBitmap->height())) { - return false; - } - - sp<Surface> surface = mSurfaceControl->getSurface(); - - Surface::SurfaceInfo surfaceInfo; - status_t status = surface->lock(&surfaceInfo); - if (status) { - LOGE("Error %d locking pointer surface before drawing.", status); - return false; - } - - SkBitmap surfaceBitmap; - ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format); - surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, surfaceInfo.w, surfaceInfo.h, bpr); - surfaceBitmap.setPixels(surfaceInfo.bits); - - SkCanvas surfaceCanvas; - surfaceCanvas.setBitmapDevice(surfaceBitmap); - - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - surfaceCanvas.drawBitmap(*mLocked.iconBitmap, 0, 0, &paint); - - status = surface->unlockAndPost(); - if (status) { - LOGE("Error %d unlocking pointer surface after drawing.", status); - return false; - } - } - - mLocked.drawn = true; - return true; -} - -bool PointerController::resizeSurfaceLocked(int32_t width, int32_t height) { - status_t status = mSurfaceComposerClient->openTransaction(); - if (status) { - LOGE("Error opening surface transaction to resize pointer surface."); - return false; - } - - status = mSurfaceControl->setSize(width, height); - if (status) { - LOGE("Error %d setting pointer surface size.", status); - return false; - } - - status = mSurfaceComposerClient->closeTransaction(); - if (status) { - LOGE("Error closing surface transaction to resize pointer surface."); - return false; - } - - return true; + mLocked.sprite->setBitmap(bitmap, hotSpotX, hotSpotY); } void PointerController::handleMessage(const Message& message) { @@ -481,7 +307,7 @@ bool PointerController::unfadeBeforeUpdateLocked() { sendFadeStepMessageDelayedLocked(getInactivityFadeDelayTimeLocked()); if (isFadingLocked()) { - mLocked.wantVisible = true; + mLocked.visible = true; mLocked.fadeAlpha = 1; return true; // update required to effect the unfade } @@ -501,11 +327,11 @@ void PointerController::startInactivityFadeDelayLocked() { } void PointerController::fadeStepLocked() { - if (mLocked.wantVisible) { + if (mLocked.visible) { mLocked.fadeAlpha -= FADE_DECAY_PER_FRAME; if (mLocked.fadeAlpha < 0) { mLocked.fadeAlpha = 0; - mLocked.wantVisible = false; + mLocked.visible = false; } else { sendFadeStepMessageDelayedLocked(FADE_FRAME_INTERVAL); } @@ -514,7 +340,7 @@ void PointerController::fadeStepLocked() { } bool PointerController::isFadingLocked() { - return !mLocked.wantVisible || mLocked.fadeAlpha != 1; + return !mLocked.visible || mLocked.fadeAlpha != 1; } nsecs_t PointerController::getInactivityFadeDelayTimeLocked() { diff --git a/services/input/PointerController.h b/services/input/PointerController.h index e1dab5c..d467a5a 100644 --- a/services/input/PointerController.h +++ b/services/input/PointerController.h @@ -17,16 +17,14 @@ #ifndef _UI_POINTER_CONTROLLER_H #define _UI_POINTER_CONTROLLER_H +#include "SpriteController.h" + #include <ui/DisplayInfo.h> #include <ui/Input.h> #include <utils/RefBase.h> #include <utils/Looper.h> #include <utils/String8.h> -#include <surfaceflinger/Surface.h> -#include <surfaceflinger/SurfaceComposerClient.h> -#include <surfaceflinger/ISurfaceComposer.h> - #include <SkBitmap.h> namespace android { @@ -86,7 +84,7 @@ public: INACTIVITY_FADE_DELAY_SHORT = 1, }; - PointerController(const sp<Looper>& looper, int32_t pointerLayer); + PointerController(const sp<Looper>& looper, const sp<SpriteController>& spriteController); virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; @@ -111,9 +109,8 @@ private: mutable Mutex mLock; sp<Looper> mLooper; - int32_t mPointerLayer; - sp<SurfaceComposerClient> mSurfaceComposerClient; - sp<SurfaceControl> mSurfaceControl; + sp<SpriteController> mSpriteController; + sp<WeakMessageHandler> mHandler; struct Locked { int32_t displayWidth; @@ -124,26 +121,17 @@ private: float pointerY; uint32_t buttonState; - SkBitmap* iconBitmap; - float iconHotSpotX; - float iconHotSpotY; - float fadeAlpha; InactivityFadeDelay inactivityFadeDelay; - bool wantVisible; bool visible; - bool drawn; - } mLocked; - sp<WeakMessageHandler> mHandler; + sp<Sprite> sprite; + } mLocked; 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(); diff --git a/services/input/SpotController.cpp b/services/input/SpotController.cpp new file mode 100644 index 0000000..dffad81 --- /dev/null +++ b/services/input/SpotController.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 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. + */ + +#define LOG_TAG "SpotController" + +//#define LOG_NDEBUG 0 + +// Log debug messages about spot updates +#define DEBUG_SPOT_UPDATES 0 + +#include "SpotController.h" + +#include <cutils/log.h> + +namespace android { + +// --- SpotController --- + +SpotController::SpotController(const sp<Looper>& looper, + const sp<SpriteController>& spriteController) : + mLooper(looper), mSpriteController(spriteController) { + mHandler = new WeakMessageHandler(this); +} + +SpotController::~SpotController() { + mLooper->removeMessages(mHandler); +} + +void SpotController:: handleMessage(const Message& message) { +} + +} // namespace android diff --git a/services/input/SpotController.h b/services/input/SpotController.h new file mode 100644 index 0000000..1d091d7 --- /dev/null +++ b/services/input/SpotController.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _UI_SPOT_CONTROLLER_H +#define _UI_SPOT_CONTROLLER_H + +#include "SpriteController.h" + +#include <utils/RefBase.h> +#include <utils/Looper.h> + +#include <SkBitmap.h> + +namespace android { + +/* + * Interface for displaying spots on screen that visually represent the positions + * of fingers on a touch pad. + * + * The spot controller is responsible for providing synchronization and for tracking + * display orientation changes if needed. + */ +class SpotControllerInterface : public virtual RefBase { +protected: + SpotControllerInterface() { } + virtual ~SpotControllerInterface() { } + +public: + +}; + + +/* + * Sprite-based spot controller implementation. + */ +class SpotController : public SpotControllerInterface, public MessageHandler { +protected: + virtual ~SpotController(); + +public: + SpotController(const sp<Looper>& looper, const sp<SpriteController>& spriteController); + +private: + mutable Mutex mLock; + + sp<Looper> mLooper; + sp<SpriteController> mSpriteController; + sp<WeakMessageHandler> mHandler; + + struct Locked { + } mLocked; + + void handleMessage(const Message& message); +}; + +} // namespace android + +#endif // _UI_SPOT_CONTROLLER_H diff --git a/services/input/SpriteController.cpp b/services/input/SpriteController.cpp new file mode 100644 index 0000000..c6d4390 --- /dev/null +++ b/services/input/SpriteController.cpp @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2011 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. + */ + +#define LOG_TAG "Sprites" + +//#define LOG_NDEBUG 0 + +#include "SpriteController.h" + +#include <cutils/log.h> +#include <utils/String8.h> + +#include <SkBitmap.h> +#include <SkCanvas.h> +#include <SkColor.h> +#include <SkPaint.h> +#include <SkXfermode.h> + +namespace android { + +// --- SpriteController --- + +SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) : + mLooper(looper), mOverlayLayer(overlayLayer) { + mHandler = new WeakMessageHandler(this); +} + +SpriteController::~SpriteController() { + mLooper->removeMessages(mHandler); + + if (mSurfaceComposerClient != NULL) { + mSurfaceComposerClient->dispose(); + mSurfaceComposerClient.clear(); + } +} + +sp<Sprite> SpriteController::createSprite() { + return new SpriteImpl(this); +} + +void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) { + bool wasEmpty = mInvalidatedSprites.isEmpty(); + mInvalidatedSprites.push(sprite); + if (wasEmpty) { + mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); + } +} + +void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) { + bool wasEmpty = mDisposedSurfaces.isEmpty(); + mDisposedSurfaces.push(surfaceControl); + if (wasEmpty) { + mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES)); + } +} + +void SpriteController::handleMessage(const Message& message) { + switch (message.what) { + case MSG_UPDATE_SPRITES: + doUpdateSprites(); + break; + case MSG_DISPOSE_SURFACES: + doDisposeSurfaces(); + break; + } +} + +void SpriteController::doUpdateSprites() { + // Collect information about sprite updates. + // Each sprite update record includes a reference to its associated sprite so we can + // be certain the sprites will not be deleted while this function runs. Sprites + // may invalidate themselves again during this time but we will handle those changes + // in the next iteration. + Vector<SpriteUpdate> updates; + size_t numSprites; + { // acquire lock + AutoMutex _l(mLock); + + numSprites = mInvalidatedSprites.size(); + for (size_t i = 0; i < numSprites; i++) { + const sp<SpriteImpl>& sprite = mInvalidatedSprites.itemAt(i); + + updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); + sprite->resetDirtyLocked(); + } + mInvalidatedSprites.clear(); + } // release lock + + // Create missing surfaces. + bool surfaceChanged = false; + for (size_t i = 0; i < numSprites; i++) { + SpriteUpdate& update = updates.editItemAt(i); + + if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { + update.state.surfaceWidth = update.state.bitmap.width(); + update.state.surfaceHeight = update.state.bitmap.height(); + update.state.surfaceDrawn = false; + update.state.surfaceVisible = false; + update.state.surfaceControl = obtainSurface( + update.state.surfaceWidth, update.state.surfaceHeight); + if (update.state.surfaceControl != NULL) { + update.surfaceChanged = surfaceChanged = true; + } + } + } + + // Resize sprites if needed, inside a global transaction. + bool haveGlobalTransaction = false; + for (size_t i = 0; i < numSprites; i++) { + SpriteUpdate& update = updates.editItemAt(i); + + if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) { + int32_t desiredWidth = update.state.bitmap.width(); + int32_t desiredHeight = update.state.bitmap.height(); + if (update.state.surfaceWidth < desiredWidth + || update.state.surfaceHeight < desiredHeight) { + if (!haveGlobalTransaction) { + SurfaceComposerClient::openGlobalTransaction(); + haveGlobalTransaction = true; + } + + status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight); + if (status) { + LOGE("Error %d resizing sprite surface from %dx%d to %dx%d", + status, update.state.surfaceWidth, update.state.surfaceHeight, + desiredWidth, desiredHeight); + } else { + update.state.surfaceWidth = desiredWidth; + update.state.surfaceHeight = desiredHeight; + update.state.surfaceDrawn = false; + update.surfaceChanged = surfaceChanged = true; + + if (update.state.surfaceVisible) { + status = update.state.surfaceControl->hide(); + if (status) { + LOGE("Error %d hiding sprite surface after resize.", status); + } else { + update.state.surfaceVisible = false; + } + } + } + } + } + } + if (haveGlobalTransaction) { + SurfaceComposerClient::closeGlobalTransaction(); + } + + // Redraw sprites if needed. + for (size_t i = 0; i < numSprites; i++) { + SpriteUpdate& update = updates.editItemAt(i); + + if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) { + update.state.surfaceDrawn = false; + update.surfaceChanged = surfaceChanged = true; + } + + if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn + && update.state.wantSurfaceVisible()) { + sp<Surface> surface = update.state.surfaceControl->getSurface(); + Surface::SurfaceInfo surfaceInfo; + status_t status = surface->lock(&surfaceInfo); + if (status) { + LOGE("Error %d locking sprite surface before drawing.", status); + } else { + SkBitmap surfaceBitmap; + ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format); + surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, + surfaceInfo.w, surfaceInfo.h, bpr); + surfaceBitmap.setPixels(surfaceInfo.bits); + + SkCanvas surfaceCanvas; + surfaceCanvas.setBitmapDevice(surfaceBitmap); + + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + surfaceCanvas.drawBitmap(update.state.bitmap, 0, 0, &paint); + + if (surfaceInfo.w > uint32_t(update.state.bitmap.width())) { + paint.setColor(0); // transparent fill color + surfaceCanvas.drawRectCoords(update.state.bitmap.width(), 0, + surfaceInfo.w, update.state.bitmap.height(), paint); + } + if (surfaceInfo.h > uint32_t(update.state.bitmap.height())) { + paint.setColor(0); // transparent fill color + surfaceCanvas.drawRectCoords(0, update.state.bitmap.height(), + surfaceInfo.w, surfaceInfo.h, paint); + } + + status = surface->unlockAndPost(); + if (status) { + LOGE("Error %d unlocking and posting sprite surface after drawing.", status); + } else { + update.state.surfaceDrawn = true; + update.surfaceChanged = surfaceChanged = true; + } + } + } + } + + // Set sprite surface properties and make them visible. + bool haveTransaction = false; + for (size_t i = 0; i < numSprites; i++) { + SpriteUpdate& update = updates.editItemAt(i); + + bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible() + && update.state.surfaceDrawn; + bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible; + bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible; + if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden + || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA + | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER + | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) { + status_t status; + if (!haveTransaction) { + status = mSurfaceComposerClient->openTransaction(); + if (status) { + LOGE("Error %d opening transation to update sprite surface.", status); + break; + } + haveTransaction = true; + } + + if (wantSurfaceVisibleAndDrawn + && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) { + status = update.state.surfaceControl->setAlpha(update.state.alpha); + if (status) { + LOGE("Error %d setting sprite surface alpha.", status); + } + } + + if (wantSurfaceVisibleAndDrawn + && (becomingVisible || (update.state.dirty & (DIRTY_POSITION + | DIRTY_HOTSPOT)))) { + status = update.state.surfaceControl->setPosition( + update.state.positionX - update.state.hotSpotX, + update.state.positionY - update.state.hotSpotY); + if (status) { + LOGE("Error %d setting sprite surface position.", status); + } + } + + if (wantSurfaceVisibleAndDrawn + && (becomingVisible + || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) { + status = update.state.surfaceControl->setMatrix( + update.state.transformationMatrix.dsdx, + update.state.transformationMatrix.dtdx, + update.state.transformationMatrix.dsdy, + update.state.transformationMatrix.dtdy); + if (status) { + LOGE("Error %d setting sprite surface transformation matrix.", status); + } + } + + int32_t surfaceLayer = mOverlayLayer + update.state.layer; + if (wantSurfaceVisibleAndDrawn + && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { + status = update.state.surfaceControl->setLayer(surfaceLayer); + if (status) { + LOGE("Error %d setting sprite surface layer.", status); + } + } + + if (becomingVisible) { + status = update.state.surfaceControl->show(surfaceLayer); + if (status) { + LOGE("Error %d showing sprite surface.", status); + } else { + update.state.surfaceVisible = true; + update.surfaceChanged = surfaceChanged = true; + } + } else if (becomingHidden) { + status = update.state.surfaceControl->hide(); + if (status) { + LOGE("Error %d hiding sprite surface.", status); + } else { + update.state.surfaceVisible = false; + update.surfaceChanged = surfaceChanged = true; + } + } + } + } + + if (haveTransaction) { + status_t status = mSurfaceComposerClient->closeTransaction(); + if (status) { + LOGE("Error %d closing transaction to update sprite surface.", status); + } + } + + // If any surfaces were changed, write back the new surface properties to the sprites. + if (surfaceChanged) { // acquire lock + AutoMutex _l(mLock); + + for (size_t i = 0; i < numSprites; i++) { + const SpriteUpdate& update = updates.itemAt(i); + + if (update.surfaceChanged) { + update.sprite->setSurfaceLocked(update.state.surfaceControl, + update.state.surfaceWidth, update.state.surfaceHeight, + update.state.surfaceDrawn, update.state.surfaceVisible); + } + } + } // release lock + + // Clear the sprite update vector outside the lock. It is very important that + // we do not clear sprite references inside the lock since we could be releasing + // the last remaining reference to the sprite here which would result in the + // sprite being deleted and the lock being reacquired by the sprite destructor + // while already held. + updates.clear(); +} + +void SpriteController::doDisposeSurfaces() { + // Collect disposed surfaces. + Vector<sp<SurfaceControl> > disposedSurfaces; + { // acquire lock + disposedSurfaces = mDisposedSurfaces; + mDisposedSurfaces.clear(); + } // release lock + + // Release the last reference to each surface outside of the lock. + // We don't want the surfaces to be deleted while we are holding our lock. + disposedSurfaces.clear(); +} + +void SpriteController::ensureSurfaceComposerClient() { + if (mSurfaceComposerClient == NULL) { + mSurfaceComposerClient = new SurfaceComposerClient(); + } +} + +sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) { + ensureSurfaceComposerClient(); + + sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface( + getpid(), String8("Sprite"), 0, width, height, PIXEL_FORMAT_RGBA_8888); + if (surfaceControl == NULL) { + LOGE("Error creating sprite surface."); + return NULL; + } + return surfaceControl; +} + + +// --- SpriteController::SpriteImpl --- + +SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) : + mController(controller), mTransactionNestingCount(0) { +} + +SpriteController::SpriteImpl::~SpriteImpl() { + AutoMutex _m(mController->mLock); + + // Let the controller take care of deleting the last reference to sprite + // surfaces so that we do not block the caller on an IPC here. + if (mState.surfaceControl != NULL) { + mController->disposeSurfaceLocked(mState.surfaceControl); + mState.surfaceControl.clear(); + } +} + +void SpriteController::SpriteImpl::setBitmap(const SkBitmap* bitmap, + float hotSpotX, float hotSpotY) { + AutoMutex _l(mController->mLock); + + if (bitmap) { + bitmap->copyTo(&mState.bitmap, SkBitmap::kARGB_8888_Config); + } else { + mState.bitmap.reset(); + } + + uint32_t dirty = DIRTY_BITMAP; + if (mState.hotSpotX != hotSpotX || mState.hotSpotY != hotSpotY) { + mState.hotSpotX = hotSpotX; + mState.hotSpotY = hotSpotY; + dirty |= DIRTY_HOTSPOT; + } + + invalidateLocked(dirty); +} + +void SpriteController::SpriteImpl::setVisible(bool visible) { + AutoMutex _l(mController->mLock); + + if (mState.visible != visible) { + mState.visible = visible; + invalidateLocked(DIRTY_VISIBILITY); + } +} + +void SpriteController::SpriteImpl::setPosition(float x, float y) { + AutoMutex _l(mController->mLock); + + if (mState.positionX != x || mState.positionY != y) { + mState.positionX = x; + mState.positionY = y; + invalidateLocked(DIRTY_POSITION); + } +} + +void SpriteController::SpriteImpl::setLayer(int32_t layer) { + AutoMutex _l(mController->mLock); + + if (mState.layer != layer) { + mState.layer = layer; + invalidateLocked(DIRTY_LAYER); + } +} + +void SpriteController::SpriteImpl::setAlpha(float alpha) { + AutoMutex _l(mController->mLock); + + if (mState.alpha != alpha) { + mState.alpha = alpha; + invalidateLocked(DIRTY_ALPHA); + } +} + +void SpriteController::SpriteImpl::setTransformationMatrix( + const SpriteTransformationMatrix& matrix) { + AutoMutex _l(mController->mLock); + + if (mState.transformationMatrix != matrix) { + mState.transformationMatrix = matrix; + invalidateLocked(DIRTY_TRANSFORMATION_MATRIX); + } +} + +void SpriteController::SpriteImpl::openTransaction() { + AutoMutex _l(mController->mLock); + + mTransactionNestingCount += 1; +} + +void SpriteController::SpriteImpl::closeTransaction() { + AutoMutex _l(mController->mLock); + + LOG_ALWAYS_FATAL_IF(mTransactionNestingCount == 0, + "Sprite closeTransaction() called but there is no open sprite transaction"); + + mTransactionNestingCount -= 1; + if (mTransactionNestingCount == 0 && mState.dirty) { + mController->invalidateSpriteLocked(this); + } +} + +void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) { + if (mTransactionNestingCount > 0) { + bool wasDirty = mState.dirty; + mState.dirty |= dirty; + if (!wasDirty) { + mController->invalidateSpriteLocked(this); + } + } +} + +} // namespace android diff --git a/services/input/SpriteController.h b/services/input/SpriteController.h new file mode 100644 index 0000000..27afb5e --- /dev/null +++ b/services/input/SpriteController.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef _UI_SPRITES_H +#define _UI_SPRITES_H + +#include <utils/RefBase.h> +#include <utils/Looper.h> + +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/SurfaceComposerClient.h> +#include <surfaceflinger/ISurfaceComposer.h> + +#include <SkBitmap.h> + +namespace android { + +/* + * Transformation matrix for a sprite. + */ +struct SpriteTransformationMatrix { + inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { } + + float dsdx; + float dtdx; + float dsdy; + float dtdy; + + inline bool operator== (const SpriteTransformationMatrix& other) { + return dsdx == other.dsdx + && dtdx == other.dtdx + && dsdy == other.dsdy + && dtdy == other.dtdy; + } + + inline bool operator!= (const SpriteTransformationMatrix& other) { + return !(*this == other); + } +}; + +/* + * A sprite is a simple graphical object that is displayed on-screen above other layers. + * The basic sprite class is an interface. + * The implementation is provided by the sprite controller. + */ +class Sprite : public RefBase { +protected: + Sprite() { } + virtual ~Sprite() { } + +public: + /* Sets the bitmap that is drawn by the sprite. + * The sprite retains a copy of the bitmap for subsequent rendering. */ + virtual void setBitmap(const SkBitmap* bitmap, float hotSpotX, float hotSpotY) = 0; + + /* Sets whether the sprite is visible. */ + virtual void setVisible(bool visible) = 0; + + /* Sets the sprite position on screen, relative to the sprite's hot spot. */ + virtual void setPosition(float x, float y) = 0; + + /* Sets the layer of the sprite, relative to the system sprite overlay layer. + * Layer 0 is the overlay layer, > 0 appear above this layer. */ + virtual void setLayer(int32_t layer) = 0; + + /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */ + virtual void setAlpha(float alpha) = 0; + + /* Sets the sprite transformation matrix. */ + virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0; + + /* Opens or closes a transaction to perform a batch of sprite updates as part of + * a single operation such as setPosition and setAlpha. It is not necessary to + * open a transaction when updating a single property. + * Calls to openTransaction() nest and must be matched by an equal number + * of calls to closeTransaction(). */ + virtual void openTransaction() = 0; + virtual void closeTransaction() = 0; +}; + +/* + * Displays sprites on the screen. + * + * This interface is used by PointerController and SpotController to draw pointers or + * spot representations of fingers. It is not intended for general purpose use + * by other components. + * + * All sprite position updates and rendering is performed asynchronously. + * + * Clients are responsible for animating sprites by periodically updating their properties. + */ +class SpriteController : public MessageHandler { +protected: + virtual ~SpriteController(); + +public: + SpriteController(const sp<Looper>& looper, int32_t overlayLayer); + + /* Creates a new sprite, initially invisible. */ + sp<Sprite> createSprite(); + +private: + enum { + MSG_UPDATE_SPRITES, + MSG_DISPOSE_SURFACES, + }; + + enum { + DIRTY_BITMAP = 1 << 0, + DIRTY_ALPHA = 1 << 1, + DIRTY_POSITION = 1 << 2, + DIRTY_TRANSFORMATION_MATRIX = 1 << 3, + DIRTY_LAYER = 1 << 4, + DIRTY_VISIBILITY = 1 << 5, + DIRTY_HOTSPOT = 1 << 6, + }; + + /* Describes the state of a sprite. + * This structure is designed so that it can be copied during updates so that + * surfaces can be resized and redrawn without blocking the client by holding a lock + * on the sprites for a long time. + * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */ + struct SpriteState { + inline SpriteState() : + dirty(0), hotSpotX(0), hotSpotY(0), visible(false), + positionX(0), positionY(0), layer(0), alpha(1.0f), + surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) { + } + + uint32_t dirty; + + SkBitmap bitmap; + float hotSpotX; + float hotSpotY; + bool visible; + float positionX; + float positionY; + int32_t layer; + float alpha; + SpriteTransformationMatrix transformationMatrix; + + sp<SurfaceControl> surfaceControl; + int32_t surfaceWidth; + int32_t surfaceHeight; + bool surfaceDrawn; + bool surfaceVisible; + + inline bool wantSurfaceVisible() const { + return visible && alpha > 0.0f && !bitmap.isNull() && !bitmap.empty(); + } + }; + + /* Client interface for a sprite. + * Requests acquire a lock on the controller, update local state and request the + * controller to invalidate the sprite. + * The real heavy lifting of creating, resizing and redrawing surfaces happens + * asynchronously with no locks held except in short critical section to copy + * the sprite state before the work and update the sprite surface control afterwards. + */ + class SpriteImpl : public Sprite { + protected: + virtual ~SpriteImpl(); + + public: + SpriteImpl(const sp<SpriteController> controller); + + virtual void setBitmap(const SkBitmap* bitmap, float hotSpotX, float hotSpotY); + virtual void setVisible(bool visible); + virtual void setPosition(float x, float y); + virtual void setLayer(int32_t layer); + virtual void setAlpha(float alpha); + virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix); + virtual void openTransaction(); + virtual void closeTransaction(); + + inline const SpriteState& getStateLocked() const { + return mState; + } + + inline void resetDirtyLocked() { + mState.dirty = 0; + } + + inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl, + int32_t width, int32_t height, bool drawn, bool visible) { + mState.surfaceControl = surfaceControl; + mState.surfaceWidth = width; + mState.surfaceHeight = height; + mState.surfaceDrawn = drawn; + mState.surfaceVisible = visible; + } + + private: + sp<SpriteController> mController; + + SpriteState mState; // guarded by mController->mLock + uint32_t mTransactionNestingCount; // guarded by mController->mLock + + void invalidateLocked(uint32_t dirty); + }; + + /* Stores temporary information collected during the sprite update cycle. */ + struct SpriteUpdate { + inline SpriteUpdate() : surfaceChanged(false) { } + inline SpriteUpdate(const sp<SpriteImpl> sprite, const SpriteState& state) : + sprite(sprite), state(state), surfaceChanged(false) { + } + + sp<SpriteImpl> sprite; + SpriteState state; + bool surfaceChanged; + }; + + mutable Mutex mLock; + + sp<Looper> mLooper; + const int32_t mOverlayLayer; + sp<WeakMessageHandler> mHandler; + + sp<SurfaceComposerClient> mSurfaceComposerClient; + + Vector<sp<SpriteImpl> > mInvalidatedSprites; // guarded by mLock + Vector<sp<SurfaceControl> > mDisposedSurfaces; // guarded by mLock + + void invalidateSpriteLocked(const sp<SpriteImpl>& sprite); + void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl); + + void handleMessage(const Message& message); + void doUpdateSprites(); + void doDisposeSurfaces(); + + void ensureSurfaceComposerClient(); + sp<SurfaceControl> obtainSurface(int32_t width, int32_t height); +}; + +} // namespace android + +#endif // _UI_SPRITES_H diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 60549c6..6feb2c7 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -192,6 +192,10 @@ private: virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) { return mPointerControllers.valueFor(deviceId); } + + virtual sp<SpotControllerInterface> obtainSpotController(int32_t device) { + return NULL; + } }; diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 426197a..7985fab 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -36,6 +36,8 @@ #include <input/InputManager.h> #include <input/PointerController.h> +#include <input/SpotController.h> +#include <input/SpriteController.h> #include <android_os_MessageQueue.h> #include <android_view_KeyEvent.h> @@ -168,6 +170,7 @@ public: virtual nsecs_t getVirtualKeyQuietTime(); virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames); virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); + virtual sp<SpotControllerInterface> obtainSpotController(int32_t deviceId); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -217,12 +220,16 @@ private: // System UI visibility. int32_t systemUiVisibility; + // Sprite controller singleton, created on first use. + sp<SpriteController> spriteController; + // Pointer controller singleton, created and destroyed as needed. wp<PointerController> pointerController; } mLocked; void updateInactivityFadeDelayLocked(const sp<PointerController>& controller); void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags); + void ensureSpriteControllerLocked(); // Power manager interactions. bool isScreenOn(); @@ -423,18 +430,15 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32 sp<PointerController> controller = mLocked.pointerController.promote(); if (controller == NULL) { - JNIEnv* env = jniEnv(); - jint layer = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.getPointerLayer); - if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) { - layer = -1; - } + ensureSpriteControllerLocked(); - controller = new PointerController(mLooper, layer); + controller = new PointerController(mLooper, mLocked.spriteController); mLocked.pointerController = controller; controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight); controller->setDisplayOrientation(mLocked.displayOrientation); + JNIEnv* env = jniEnv(); jobject iconObj = env->CallObjectMethod(mCallbacksObj, gCallbacksClassInfo.getPointerIcon); if (!checkAndClearExceptionFromCallback(env, "getPointerIcon") && iconObj) { jfloat iconHotSpotX = env->GetFloatField(iconObj, gPointerIconClassInfo.hotSpotX); @@ -455,6 +459,24 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32 return controller; } +sp<SpotControllerInterface> NativeInputManager::obtainSpotController(int32_t deviceId) { + AutoMutex _l(mLock); + + ensureSpriteControllerLocked(); + return new SpotController(mLooper, mLocked.spriteController); +} + +void NativeInputManager::ensureSpriteControllerLocked() { + if (mLocked.spriteController == NULL) { + JNIEnv* env = jniEnv(); + jint layer = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.getPointerLayer); + if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) { + layer = -1; + } + mLocked.spriteController = new SpriteController(mLooper, layer); + } +} + void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, uint32_t policyFlags) { #if DEBUG_INPUT_DISPATCHER_POLICY |
