am a6dbfdd3: Add a sprite controller. (DO NOT MERGE)
* commit 'a6dbfdd3a858aac52cc87f80f91e8eef7d613605':
Add a sprite controller. (DO NOT MERGE)
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 @@
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 @@
/* 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 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 @@
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();
- }
+ AutoMutex _l(mLock);
- if (mSurfaceComposerClient != NULL) {
- mSurfaceComposerClient->dispose();
- mSurfaceComposerClient.clear();
- }
-
- delete mLocked.iconBitmap;
+ mLocked.sprite.clear();
}
bool PointerController::getBounds(float* outMinX, float* outMinY,
@@ -214,75 +203,11 @@
}
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 @@
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::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 @@
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::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 @@
}
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 @@
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 @@
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 @@
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..c6d4390f
--- /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 @@
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 @@
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 @@
// 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<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 @@
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