am e8dc05aa: am a6dbfdd3: Add a sprite controller. (DO NOT MERGE)

* commit 'e8dc05aa6d2f4138729438281485ca10d854dc8d':
  Add a sprite controller. (DO NOT MERGE)
This commit is contained in:
Jeff Brown
2011-05-25 14:46:50 -07:00
committed by Android Git Automerger
10 changed files with 904 additions and 219 deletions

View File

@ -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 \

View File

@ -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;
};

View File

@ -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();
}
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::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() {

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
};

View File

@ -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