diff options
| author | 2011-05-25 14:46:50 -0700 | |
|---|---|---|
| committer | 2011-05-25 14:46:50 -0700 | |
| commit | 13412d31650366f41b1f3d9f429cb0a01dd575ef (patch) | |
| tree | 1f29fcbbd75db718a514fcd0609242758d68b2e9 | |
| parent | fbc67977aecfd94e8923e8eca3b859cd431c94b8 (diff) | |
| parent | e8dc05aa6d2f4138729438281485ca10d854dc8d (diff) | |
am e8dc05aa: am a6dbfdd3: Add a sprite controller. (DO NOT MERGE)
* commit 'e8dc05aa6d2f4138729438281485ca10d854dc8d':
  Add a sprite controller. (DO NOT MERGE)
| -rw-r--r-- | services/input/Android.mk | 4 | ||||
| -rw-r--r-- | services/input/InputReader.h | 4 | ||||
| -rw-r--r-- | services/input/PointerController.cpp | 212 | ||||
| -rw-r--r-- | services/input/PointerController.h | 26 | ||||
| -rw-r--r-- | services/input/SpotController.cpp | 45 | ||||
| -rw-r--r-- | services/input/SpotController.h | 71 | ||||
| -rw-r--r-- | services/input/SpriteController.cpp | 472 | ||||
| -rw-r--r-- | services/input/SpriteController.h | 251 | ||||
| -rw-r--r-- | services/input/tests/InputReader_test.cpp | 4 | ||||
| -rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 34 | 
10 files changed, 904 insertions, 219 deletions
diff --git a/services/input/Android.mk b/services/input/Android.mk index d7b61fc9592e..58b531886db1 100644 --- a/services/input/Android.mk +++ b/services/input/Android.mk @@ -22,7 +22,9 @@ LOCAL_SRC_FILES:= \      InputManager.cpp \      InputReader.cpp \      InputWindow.cpp \ -    PointerController.cpp +    PointerController.cpp \ +    SpotController.cpp \ +    SpriteController.cpp  LOCAL_SHARED_LIBRARIES := \      libcutils \ diff --git a/services/input/InputReader.h b/services/input/InputReader.h index cf9b13de39c6..9ed1391301a7 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -20,6 +20,7 @@  #include "EventHub.h"  #include "InputDispatcher.h"  #include "PointerController.h" +#include "SpotController.h"  #include <ui/Input.h>  #include <ui/DisplayInfo.h> @@ -89,6 +90,9 @@ public:      /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */      virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0; + +    /* Gets a spot controller associated with the specified touch pad device. */ +    virtual sp<SpotControllerInterface> obtainSpotController(int32_t deviceId) = 0;  }; diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp index a4ee295a73b1..15effb7f7951 100644 --- a/services/input/PointerController.cpp +++ b/services/input/PointerController.cpp @@ -49,8 +49,11 @@ static const nsecs_t FADE_FRAME_INTERVAL = 1000000000LL / 60;  static const float FADE_DECAY_PER_FRAME = float(FADE_FRAME_INTERVAL) / FADE_DURATION; -PointerController::PointerController(const sp<Looper>& looper, int32_t pointerLayer) : -        mLooper(looper), mPointerLayer(pointerLayer) { +PointerController::PointerController(const sp<Looper>& looper, +        const sp<SpriteController>& spriteController) : +        mLooper(looper), mSpriteController(spriteController) { +    mHandler = new WeakMessageHandler(this); +      AutoMutex _l(mLock);      mLocked.displayWidth = -1; @@ -61,34 +64,20 @@ PointerController::PointerController(const sp<Looper>& looper, int32_t pointerLa      mLocked.pointerY = 0;      mLocked.buttonState = 0; -    mLocked.iconBitmap = NULL; -    mLocked.iconHotSpotX = 0; -    mLocked.iconHotSpotY = 0; -      mLocked.fadeAlpha = 1;      mLocked.inactivityFadeDelay = INACTIVITY_FADE_DELAY_NORMAL; -    mLocked.wantVisible = false;      mLocked.visible = false; -    mLocked.drawn = false; -    mHandler = new WeakMessageHandler(this); +    mLocked.sprite = mSpriteController->createSprite();  }  PointerController::~PointerController() {      mLooper->removeMessages(mHandler); -    if (mSurfaceControl != NULL) { -        mSurfaceControl->clear(); -        mSurfaceControl.clear(); -    } - -    if (mSurfaceComposerClient != NULL) { -        mSurfaceComposerClient->dispose(); -        mSurfaceComposerClient.clear(); -    } +    AutoMutex _l(mLock); -    delete mLocked.iconBitmap; +    mLocked.sprite.clear();  }  bool PointerController::getBounds(float* outMinX, float* outMinY, @@ -214,75 +203,11 @@ void PointerController::setInactivityFadeDelay(InactivityFadeDelay inactivityFad  }  void PointerController::updateLocked() { -    bool wantVisibleAndHavePointerIcon = mLocked.wantVisible && mLocked.iconBitmap; - -    if (wantVisibleAndHavePointerIcon) { -        // Want the pointer to be visible. -        // Ensure the surface is created and drawn. -        if (!createSurfaceIfNeededLocked() || !drawPointerIfNeededLocked()) { -            return; -        } -    } else { -        // Don't want the pointer to be visible. -        // If it is not visible then we are done. -        if (mSurfaceControl == NULL || !mLocked.visible) { -            return; -        } -    } - -    status_t status = mSurfaceComposerClient->openTransaction(); -    if (status) { -        LOGE("Error opening surface transaction to update pointer surface."); -        return; -    } - -    if (wantVisibleAndHavePointerIcon) { -        status = mSurfaceControl->setPosition( -                mLocked.pointerX - mLocked.iconHotSpotX, -                mLocked.pointerY - mLocked.iconHotSpotY); -        if (status) { -            LOGE("Error %d moving pointer surface.", status); -            goto CloseTransaction; -        } - -        status = mSurfaceControl->setAlpha(mLocked.fadeAlpha); -        if (status) { -            LOGE("Error %d setting pointer surface alpha.", status); -            goto CloseTransaction; -        } - -        if (!mLocked.visible) { -            status = mSurfaceControl->setLayer(mPointerLayer); -            if (status) { -                LOGE("Error %d setting pointer surface layer.", status); -                goto CloseTransaction; -            } - -            status = mSurfaceControl->show(mPointerLayer); -            if (status) { -                LOGE("Error %d showing pointer surface.", status); -                goto CloseTransaction; -            } - -            mLocked.visible = true; -        } -    } else { -        if (mLocked.visible) { -            status = mSurfaceControl->hide(); -            if (status) { -                LOGE("Error %d hiding pointer surface.", status); -                goto CloseTransaction; -            } - -            mLocked.visible = false; -        } -    } - -CloseTransaction: -    status = mSurfaceComposerClient->closeTransaction(); -    if (status) { -        LOGE("Error closing surface transaction to update pointer surface."); -    } +    mLocked.sprite->openTransaction(); +    mLocked.sprite->setPosition(mLocked.pointerX, mLocked.pointerY); +    mLocked.sprite->setAlpha(mLocked.fadeAlpha); +    mLocked.sprite->setVisible(mLocked.visible); +    mLocked.sprite->closeTransaction();  }  void PointerController::setDisplaySize(int32_t width, int32_t height) { @@ -339,7 +264,7 @@ void PointerController::setDisplayOrientation(int32_t orientation) {          case DISPLAY_ORIENTATION_90:              temp = x;              x = y; -            y = mLocked.displayWidth - x; +            y = mLocked.displayWidth - temp;              break;          case DISPLAY_ORIENTATION_180:              x = mLocked.displayWidth - x; @@ -365,106 +290,7 @@ void PointerController::setDisplayOrientation(int32_t orientation) {  void PointerController::setPointerIcon(const SkBitmap* bitmap, float hotSpotX, float hotSpotY) {      AutoMutex _l(mLock); -    if (mLocked.iconBitmap) { -        delete mLocked.iconBitmap; -        mLocked.iconBitmap = NULL; -    } - -    if (bitmap) { -        mLocked.iconBitmap = new SkBitmap(); -        bitmap->copyTo(mLocked.iconBitmap, SkBitmap::kARGB_8888_Config); -    } - -    mLocked.iconHotSpotX = hotSpotX; -    mLocked.iconHotSpotY = hotSpotY; -    mLocked.drawn = false; -} - -bool PointerController::createSurfaceIfNeededLocked() { -    if (!mLocked.iconBitmap) { -        // If we don't have a pointer icon, then no point allocating a surface now. -        return false; -    } - -    if (mSurfaceComposerClient == NULL) { -        mSurfaceComposerClient = new SurfaceComposerClient(); -    } - -    if (mSurfaceControl == NULL) { -        mSurfaceControl = mSurfaceComposerClient->createSurface(getpid(), -                String8("Pointer Icon"), 0, -                mLocked.iconBitmap->width(), mLocked.iconBitmap->height(), -                PIXEL_FORMAT_RGBA_8888); -        if (mSurfaceControl == NULL) { -            LOGE("Error creating pointer surface."); -            return false; -        } -    } -    return true; -} - -bool PointerController::drawPointerIfNeededLocked() { -    if (!mLocked.drawn) { -        if (!mLocked.iconBitmap) { -            return false; -        } - -        if (!resizeSurfaceLocked(mLocked.iconBitmap->width(), mLocked.iconBitmap->height())) { -            return false; -        } - -        sp<Surface> surface = mSurfaceControl->getSurface(); - -        Surface::SurfaceInfo surfaceInfo; -        status_t status = surface->lock(&surfaceInfo); -        if (status) { -            LOGE("Error %d locking pointer surface before drawing.", status); -            return false; -        } - -        SkBitmap surfaceBitmap; -        ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format); -        surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, surfaceInfo.w, surfaceInfo.h, bpr); -        surfaceBitmap.setPixels(surfaceInfo.bits); - -        SkCanvas surfaceCanvas; -        surfaceCanvas.setBitmapDevice(surfaceBitmap); - -        SkPaint paint; -        paint.setXfermodeMode(SkXfermode::kSrc_Mode); -        surfaceCanvas.drawBitmap(*mLocked.iconBitmap, 0, 0, &paint); - -        status = surface->unlockAndPost(); -        if (status) { -            LOGE("Error %d unlocking pointer surface after drawing.", status); -            return false; -        } -    } - -    mLocked.drawn = true; -    return true; -} - -bool PointerController::resizeSurfaceLocked(int32_t width, int32_t height) { -    status_t status = mSurfaceComposerClient->openTransaction(); -    if (status) { -        LOGE("Error opening surface transaction to resize pointer surface."); -        return false; -    } - -    status = mSurfaceControl->setSize(width, height); -    if (status) { -        LOGE("Error %d setting pointer surface size.", status); -        return false; -    } - -    status = mSurfaceComposerClient->closeTransaction(); -    if (status) { -        LOGE("Error closing surface transaction to resize pointer surface."); -        return false; -    } - -    return true; +    mLocked.sprite->setBitmap(bitmap, hotSpotX, hotSpotY);  }  void PointerController::handleMessage(const Message& message) { @@ -481,7 +307,7 @@ bool PointerController::unfadeBeforeUpdateLocked() {      sendFadeStepMessageDelayedLocked(getInactivityFadeDelayTimeLocked());      if (isFadingLocked()) { -        mLocked.wantVisible = true; +        mLocked.visible = true;          mLocked.fadeAlpha = 1;          return true; // update required to effect the unfade      } @@ -501,11 +327,11 @@ void PointerController::startInactivityFadeDelayLocked() {  }  void PointerController::fadeStepLocked() { -    if (mLocked.wantVisible) { +    if (mLocked.visible) {          mLocked.fadeAlpha -= FADE_DECAY_PER_FRAME;          if (mLocked.fadeAlpha < 0) {              mLocked.fadeAlpha = 0; -            mLocked.wantVisible = false; +            mLocked.visible = false;          } else {              sendFadeStepMessageDelayedLocked(FADE_FRAME_INTERVAL);          } @@ -514,7 +340,7 @@ void PointerController::fadeStepLocked() {  }  bool PointerController::isFadingLocked() { -    return !mLocked.wantVisible || mLocked.fadeAlpha != 1; +    return !mLocked.visible || mLocked.fadeAlpha != 1;  }  nsecs_t PointerController::getInactivityFadeDelayTimeLocked() { diff --git a/services/input/PointerController.h b/services/input/PointerController.h index e1dab5c78313..d467a5a01bcd 100644 --- a/services/input/PointerController.h +++ b/services/input/PointerController.h @@ -17,16 +17,14 @@  #ifndef _UI_POINTER_CONTROLLER_H  #define _UI_POINTER_CONTROLLER_H +#include "SpriteController.h" +  #include <ui/DisplayInfo.h>  #include <ui/Input.h>  #include <utils/RefBase.h>  #include <utils/Looper.h>  #include <utils/String8.h> -#include <surfaceflinger/Surface.h> -#include <surfaceflinger/SurfaceComposerClient.h> -#include <surfaceflinger/ISurfaceComposer.h> -  #include <SkBitmap.h>  namespace android { @@ -86,7 +84,7 @@ public:          INACTIVITY_FADE_DELAY_SHORT = 1,      }; -    PointerController(const sp<Looper>& looper, int32_t pointerLayer); +    PointerController(const sp<Looper>& looper, const sp<SpriteController>& spriteController);      virtual bool getBounds(float* outMinX, float* outMinY,              float* outMaxX, float* outMaxY) const; @@ -111,9 +109,8 @@ private:      mutable Mutex mLock;      sp<Looper> mLooper; -    int32_t mPointerLayer; -    sp<SurfaceComposerClient> mSurfaceComposerClient; -    sp<SurfaceControl> mSurfaceControl; +    sp<SpriteController> mSpriteController; +    sp<WeakMessageHandler> mHandler;      struct Locked {          int32_t displayWidth; @@ -124,26 +121,17 @@ private:          float pointerY;          uint32_t buttonState; -        SkBitmap* iconBitmap; -        float iconHotSpotX; -        float iconHotSpotY; -          float fadeAlpha;          InactivityFadeDelay inactivityFadeDelay; -        bool wantVisible;          bool visible; -        bool drawn; -    } mLocked; -    sp<WeakMessageHandler> mHandler; +        sp<Sprite> sprite; +    } mLocked;      bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;      void setPositionLocked(float x, float y);      void updateLocked(); -    bool createSurfaceIfNeededLocked(); -    bool drawPointerIfNeededLocked(); -    bool resizeSurfaceLocked(int32_t width, int32_t height);      void handleMessage(const Message& message);      bool unfadeBeforeUpdateLocked(); diff --git a/services/input/SpotController.cpp b/services/input/SpotController.cpp new file mode 100644 index 000000000000..dffad81009c7 --- /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 000000000000..1d091d7e2aa0 --- /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 000000000000..c6d4390fcc92 --- /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 000000000000..27afb5ecbd82 --- /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 60549c65fd0a..6feb2c7f85ef 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -192,6 +192,10 @@ private:      virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) {          return mPointerControllers.valueFor(deviceId);      } + +    virtual sp<SpotControllerInterface> obtainSpotController(int32_t device) { +        return NULL; +    }  }; diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 426197a97289..7985fab08d54 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -36,6 +36,8 @@  #include <input/InputManager.h>  #include <input/PointerController.h> +#include <input/SpotController.h> +#include <input/SpriteController.h>  #include <android_os_MessageQueue.h>  #include <android_view_KeyEvent.h> @@ -168,6 +170,7 @@ public:      virtual nsecs_t getVirtualKeyQuietTime();      virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);      virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); +    virtual sp<SpotControllerInterface> obtainSpotController(int32_t deviceId);      /* --- InputDispatcherPolicyInterface implementation --- */ @@ -217,12 +220,16 @@ private:          // System UI visibility.          int32_t systemUiVisibility; +        // Sprite controller singleton, created on first use. +        sp<SpriteController> spriteController; +          // Pointer controller singleton, created and destroyed as needed.          wp<PointerController> pointerController;      } mLocked;      void updateInactivityFadeDelayLocked(const sp<PointerController>& controller);      void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags); +    void ensureSpriteControllerLocked();      // Power manager interactions.      bool isScreenOn(); @@ -423,18 +430,15 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32      sp<PointerController> controller = mLocked.pointerController.promote();      if (controller == NULL) { -        JNIEnv* env = jniEnv(); -        jint layer = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.getPointerLayer); -        if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) { -            layer = -1; -        } +        ensureSpriteControllerLocked(); -        controller = new PointerController(mLooper, layer); +        controller = new PointerController(mLooper, mLocked.spriteController);          mLocked.pointerController = controller;          controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight);          controller->setDisplayOrientation(mLocked.displayOrientation); +        JNIEnv* env = jniEnv();          jobject iconObj = env->CallObjectMethod(mCallbacksObj, gCallbacksClassInfo.getPointerIcon);          if (!checkAndClearExceptionFromCallback(env, "getPointerIcon") && iconObj) {              jfloat iconHotSpotX = env->GetFloatField(iconObj, gPointerIconClassInfo.hotSpotX); @@ -455,6 +459,24 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32      return controller;  } +sp<SpotControllerInterface> NativeInputManager::obtainSpotController(int32_t deviceId) { +    AutoMutex _l(mLock); + +    ensureSpriteControllerLocked(); +    return new SpotController(mLooper, mLocked.spriteController); +} + +void NativeInputManager::ensureSpriteControllerLocked() { +    if (mLocked.spriteController == NULL) { +        JNIEnv* env = jniEnv(); +        jint layer = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.getPointerLayer); +        if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) { +            layer = -1; +        } +        mLocked.spriteController = new SpriteController(mLooper, layer); +    } +} +  void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode,          int32_t switchValue, uint32_t policyFlags) {  #if DEBUG_INPUT_DISPATCHER_POLICY  |