* commit 'e8dc05aa6d2f4138729438281485ca10d854dc8d': Add a sprite controller. (DO NOT MERGE)
This commit is contained in:
@ -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 \
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
45
services/input/SpotController.cpp
Normal file
45
services/input/SpotController.cpp
Normal 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
|
71
services/input/SpotController.h
Normal file
71
services/input/SpotController.h
Normal 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
|
472
services/input/SpriteController.cpp
Normal file
472
services/input/SpriteController.cpp
Normal 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
|
251
services/input/SpriteController.h
Normal file
251
services/input/SpriteController.h
Normal 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
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user