зеркало из https://github.com/mozilla/pjs.git
Bug 743907 - Add cursor mapper support back to libui, r=cjones
This commit is contained in:
Родитель
e58e02c283
Коммит
8191ac643c
|
@ -74,6 +74,8 @@ CPPSRCS = \
|
|||
KeyLayoutMap.cpp \
|
||||
PixelFormat.cpp \
|
||||
VirtualKeyMap.cpp \
|
||||
PointerController.cpp \
|
||||
SpriteController.cpp \
|
||||
PropertyMap.cpp \
|
||||
Unicode.cpp \
|
||||
Timers.cpp \
|
||||
|
|
|
@ -422,12 +422,10 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
|
|||
device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Cursor-like devices.
|
||||
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
|
||||
device->addMapper(new CursorInputMapper(device));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Touchscreens and touchpad devices.
|
||||
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
|
||||
|
@ -2004,7 +2002,6 @@ void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState,
|
|||
|
||||
// --- CursorInputMapper ---
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
CursorInputMapper::CursorInputMapper(InputDevice* device) :
|
||||
InputMapper(device) {
|
||||
}
|
||||
|
@ -2021,12 +2018,10 @@ void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
|
|||
|
||||
if (mParameters.mode == Parameters::MODE_POINTER) {
|
||||
float minX, minY, maxX, maxY;
|
||||
#if 0
|
||||
if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
|
||||
info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f);
|
||||
info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale);
|
||||
info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale);
|
||||
|
@ -2078,7 +2073,7 @@ void CursorInputMapper::configure(nsecs_t when,
|
|||
mYPrecision = 1.0f;
|
||||
mXScale = 1.0f;
|
||||
mYScale = 1.0f;
|
||||
//mPointerController = getPolicy()->obtainPointerController(getDeviceId());
|
||||
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
|
||||
break;
|
||||
case Parameters::MODE_NAVIGATION:
|
||||
mSource = AINPUT_SOURCE_TRACKBALL;
|
||||
|
@ -2225,7 +2220,6 @@ void CursorInputMapper::sync(nsecs_t when) {
|
|||
|
||||
mPointerVelocityControl.move(when, &deltaX, &deltaY);
|
||||
|
||||
#if 0
|
||||
if (mPointerController != NULL) {
|
||||
if (moved || scrolled || buttonsChanged) {
|
||||
mPointerController->setPresentation(
|
||||
|
@ -2247,10 +2241,9 @@ void CursorInputMapper::sync(nsecs_t when) {
|
|||
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
|
||||
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
|
||||
} else {
|
||||
#endif
|
||||
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
|
||||
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
|
||||
// }
|
||||
}
|
||||
|
||||
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
|
||||
|
||||
|
@ -2273,8 +2266,7 @@ void CursorInputMapper::sync(nsecs_t when) {
|
|||
int32_t motionEventAction;
|
||||
if (downChanged) {
|
||||
motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
|
||||
//} else if (down || mPointerController == NULL) {
|
||||
} else if (1) {
|
||||
} else if (down || mPointerController == NULL) {
|
||||
motionEventAction = AMOTION_EVENT_ACTION_MOVE;
|
||||
} else {
|
||||
motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
|
||||
|
@ -2286,7 +2278,6 @@ void CursorInputMapper::sync(nsecs_t when) {
|
|||
getListener()->notifyMotion(&args);
|
||||
|
||||
// Send hover move after UP to tell the application that the mouse is hovering now.
|
||||
#if 0
|
||||
if (motionEventAction == AMOTION_EVENT_ACTION_UP
|
||||
&& mPointerController != NULL) {
|
||||
NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
|
||||
|
@ -2295,7 +2286,6 @@ void CursorInputMapper::sync(nsecs_t when) {
|
|||
1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime);
|
||||
getListener()->notifyMotion(&hoverArgs);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Send scroll events.
|
||||
if (scrolled) {
|
||||
|
@ -2332,7 +2322,6 @@ void CursorInputMapper::fadePointer() {
|
|||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_ANDROID_OS
|
||||
|
||||
// --- TouchInputMapper ---
|
||||
|
||||
|
@ -2701,13 +2690,11 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
|
|||
// Create pointer controller if needed.
|
||||
if (mDeviceMode == DEVICE_MODE_POINTER ||
|
||||
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
|
||||
#if 0
|
||||
if (mPointerController == NULL) {
|
||||
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//mPointerController.clear();
|
||||
mPointerController.clear();
|
||||
}
|
||||
|
||||
bool orientationChanged = mSurfaceOrientation != orientation;
|
||||
|
@ -3295,12 +3282,10 @@ void TouchInputMapper::reset(nsecs_t when) {
|
|||
mPointerGesture.reset();
|
||||
mPointerSimple.reset();
|
||||
|
||||
#if 0
|
||||
if (mPointerController != NULL) {
|
||||
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
|
||||
mPointerController->clearSpots();
|
||||
}
|
||||
#endif
|
||||
|
||||
InputMapper::reset(when);
|
||||
}
|
||||
|
@ -3437,7 +3422,6 @@ void TouchInputMapper::sync(nsecs_t when) {
|
|||
|
||||
dispatchPointerUsage(when, policyFlags, pointerUsage);
|
||||
} else {
|
||||
#if 0
|
||||
if (mDeviceMode == DEVICE_MODE_DIRECT
|
||||
&& mConfig.showTouches && mPointerController != NULL) {
|
||||
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
|
||||
|
@ -3448,7 +3432,6 @@ void TouchInputMapper::sync(nsecs_t when) {
|
|||
mCurrentCookedPointerData.idToIndex,
|
||||
mCurrentCookedPointerData.touchingIdBits);
|
||||
}
|
||||
#endif
|
||||
|
||||
dispatchHoverExit(when, policyFlags);
|
||||
dispatchTouches(when, policyFlags);
|
||||
|
@ -3982,7 +3965,6 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
|
|||
}
|
||||
|
||||
// Update the pointer presentation and spots.
|
||||
#if 0
|
||||
if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
|
||||
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
|
||||
if (finishPreviousGesture || cancelPreviousGesture) {
|
||||
|
@ -4026,7 +4008,6 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
|
|||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Send events!
|
||||
int32_t metaState = getContext()->getGlobalMetaState();
|
||||
|
@ -4139,7 +4120,6 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
|
|||
// the pointer is hovering again even if the user is not currently touching
|
||||
// the touch pad. This ensures that a view will receive a fresh hover enter
|
||||
// event after a tap.
|
||||
#if 0
|
||||
float x, y;
|
||||
mPointerController->getPosition(&x, &y);
|
||||
|
||||
|
@ -4158,7 +4138,6 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
|
|||
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
|
||||
1, &pointerProperties, &pointerCoords, 0, 0, mPointerGesture.downTime);
|
||||
getListener()->notifyMotion(&args);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Update state.
|
||||
|
@ -4198,12 +4177,10 @@ void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags)
|
|||
mPointerVelocityControl.reset();
|
||||
|
||||
// Remove any current spots.
|
||||
#if 0
|
||||
if (mPointerController != NULL) {
|
||||
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
|
||||
mPointerController->clearSpots();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TouchInputMapper::preparePointerGestures(nsecs_t when,
|
||||
|
@ -4393,13 +4370,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
|
|||
// Move the pointer using a relative motion.
|
||||
// When using spots, the click will occur at the position of the anchor
|
||||
// spot and all other spots will move there.
|
||||
//mPointerController->move(deltaX, deltaY);
|
||||
mPointerController->move(deltaX, deltaY);
|
||||
} else {
|
||||
mPointerVelocityControl.reset();
|
||||
}
|
||||
|
||||
float x, y;
|
||||
//mPointerController->getPosition(&x, &y);
|
||||
mPointerController->getPosition(&x, &y);
|
||||
|
||||
mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG;
|
||||
mPointerGesture.currentGestureIdBits.clear();
|
||||
|
@ -4426,7 +4403,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
|
|||
&& lastFingerCount == 1) {
|
||||
if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
|
||||
float x, y;
|
||||
//mPointerController->getPosition(&x, &y);
|
||||
mPointerController->getPosition(&x, &y);
|
||||
if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop
|
||||
&& fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
|
||||
#if DEBUG_GESTURES
|
||||
|
@ -4494,7 +4471,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
|
|||
if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
|
||||
if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
|
||||
float x, y;
|
||||
//mPointerController->getPosition(&x, &y);
|
||||
mPointerController->getPosition(&x, &y);
|
||||
if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop
|
||||
&& fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
|
||||
mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
|
||||
|
@ -4530,7 +4507,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
|
|||
|
||||
// Move the pointer using a relative motion.
|
||||
// When using spots, the hover or drag will occur at the position of the anchor spot.
|
||||
//mPointerController->move(deltaX, deltaY);
|
||||
mPointerController->move(deltaX, deltaY);
|
||||
} else {
|
||||
mPointerVelocityControl.reset();
|
||||
}
|
||||
|
@ -4553,7 +4530,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
|
|||
}
|
||||
|
||||
float x, y;
|
||||
//mPointerController->getPosition(&x, &y);
|
||||
mPointerController->getPosition(&x, &y);
|
||||
|
||||
mPointerGesture.currentGestureIdBits.clear();
|
||||
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
|
||||
|
@ -4627,8 +4604,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
|
|||
mCurrentRawPointerData.getCentroidOfTouchingPointers(
|
||||
&mPointerGesture.referenceTouchX,
|
||||
&mPointerGesture.referenceTouchY);
|
||||
//mPointerController->getPosition(&mPointerGesture.referenceGestureX,
|
||||
// &mPointerGesture.referenceGestureY);
|
||||
mPointerController->getPosition(&mPointerGesture.referenceGestureX,
|
||||
&mPointerGesture.referenceGestureY);
|
||||
}
|
||||
|
||||
// Clear the reference deltas for fingers not yet included in the reference calculation.
|
||||
|
@ -4920,7 +4897,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when,
|
|||
}
|
||||
}
|
||||
|
||||
//mPointerController->setButtonState(mCurrentButtonState);
|
||||
mPointerController->setButtonState(mCurrentButtonState);
|
||||
|
||||
#if DEBUG_GESTURES
|
||||
ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
|
||||
|
@ -4967,12 +4944,12 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags)
|
|||
uint32_t index = mCurrentCookedPointerData.idToIndex[id];
|
||||
float x = mCurrentCookedPointerData.pointerCoords[index].getX();
|
||||
float y = mCurrentCookedPointerData.pointerCoords[index].getY();
|
||||
//mPointerController->setPosition(x, y);
|
||||
mPointerController->setPosition(x, y);
|
||||
|
||||
hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id);
|
||||
down = !hovering;
|
||||
|
||||
//mPointerController->getPosition(&x, &y);
|
||||
mPointerController->getPosition(&x, &y);
|
||||
mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]);
|
||||
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
|
||||
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
|
||||
|
@ -5011,7 +4988,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags)
|
|||
rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
|
||||
mPointerVelocityControl.move(when, &deltaX, &deltaY);
|
||||
|
||||
//mPointerController->move(deltaX, deltaY);
|
||||
mPointerController->move(deltaX, deltaY);
|
||||
} else {
|
||||
mPointerVelocityControl.reset();
|
||||
}
|
||||
|
@ -5020,7 +4997,7 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags)
|
|||
hovering = !down;
|
||||
|
||||
float x, y;
|
||||
//mPointerController->getPosition(&x, &y);
|
||||
mPointerController->getPosition(&x, &y);
|
||||
mPointerSimple.currentCoords.copyFrom(
|
||||
mCurrentCookedPointerData.pointerCoords[currentIndex]);
|
||||
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
|
||||
|
@ -5050,7 +5027,6 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
|
|||
bool down, bool hovering) {
|
||||
int32_t metaState = getContext()->getGlobalMetaState();
|
||||
|
||||
#if 0
|
||||
if (mPointerController != NULL) {
|
||||
if (down || hovering) {
|
||||
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
|
||||
|
@ -5061,7 +5037,6 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
|
|||
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mPointerSimple.down && !down) {
|
||||
mPointerSimple.down = false;
|
||||
|
@ -5240,11 +5215,9 @@ bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties
|
|||
}
|
||||
|
||||
void TouchInputMapper::fadePointer() {
|
||||
#if 0
|
||||
if (mPointerController != NULL) {
|
||||
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
#define _UI_INPUT_READER_H
|
||||
|
||||
#include "EventHub.h"
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
#include "PointerController.h"
|
||||
#endif
|
||||
#include "InputListener.h"
|
||||
|
||||
#include "Input.h"
|
||||
|
@ -209,10 +207,8 @@ public:
|
|||
/* Gets the input reader configuration. */
|
||||
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0;
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
/* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */
|
||||
virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -938,7 +934,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
class CursorInputMapper : public InputMapper {
|
||||
public:
|
||||
CursorInputMapper(InputDevice* device);
|
||||
|
@ -1002,7 +997,6 @@ private:
|
|||
|
||||
void sync(nsecs_t when);
|
||||
};
|
||||
#endif // HAVE_ANDROID_OS
|
||||
|
||||
|
||||
class TouchInputMapper : public InputMapper {
|
||||
|
@ -1176,10 +1170,8 @@ protected:
|
|||
// The time the primary pointer last went down.
|
||||
nsecs_t mDownTime;
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
// The pointer controller, or null if the device is not a pointer.
|
||||
sp<PointerControllerInterface> mPointerController;
|
||||
#endif
|
||||
|
||||
Vector<VirtualKey> mVirtualKeys;
|
||||
|
||||
|
|
|
@ -0,0 +1,601 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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 "PointerController"
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
// Log debug messages about pointer updates
|
||||
#define DEBUG_POINTER_UPDATES 0
|
||||
|
||||
#include "PointerController.h"
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
#include <SkCanvas.h>
|
||||
#include <SkColor.h>
|
||||
#include <SkPaint.h>
|
||||
#include <SkXfermode.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- PointerController ---
|
||||
|
||||
// Time to wait before starting the fade when the pointer is inactive.
|
||||
static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
|
||||
static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
|
||||
|
||||
// Time to wait between animation frames.
|
||||
static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60;
|
||||
|
||||
// Time to spend fading out the spot completely.
|
||||
static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
|
||||
|
||||
// Time to spend fading out the pointer completely.
|
||||
static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
|
||||
|
||||
|
||||
// --- PointerController ---
|
||||
|
||||
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
|
||||
const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
|
||||
mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
|
||||
mHandler = new WeakMessageHandler(this);
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mLocked.animationPending = false;
|
||||
|
||||
mLocked.displayWidth = -1;
|
||||
mLocked.displayHeight = -1;
|
||||
mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
|
||||
|
||||
mLocked.presentation = PRESENTATION_POINTER;
|
||||
mLocked.presentationChanged = false;
|
||||
|
||||
mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL;
|
||||
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
mLocked.pointerX = 0;
|
||||
mLocked.pointerY = 0;
|
||||
mLocked.pointerAlpha = 0.0f; // pointer is initially faded
|
||||
mLocked.pointerSprite = mSpriteController->createSprite();
|
||||
mLocked.pointerIconChanged = false;
|
||||
|
||||
mLocked.buttonState = 0;
|
||||
|
||||
loadResources();
|
||||
}
|
||||
|
||||
PointerController::~PointerController() {
|
||||
mLooper->removeMessages(mHandler);
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mLocked.pointerSprite.clear();
|
||||
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
delete mLocked.spots.itemAt(i);
|
||||
}
|
||||
mLocked.spots.clear();
|
||||
mLocked.recycledSprites.clear();
|
||||
}
|
||||
|
||||
bool PointerController::getBounds(float* outMinX, float* outMinY,
|
||||
float* outMaxX, float* outMaxY) const {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
|
||||
}
|
||||
|
||||
bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
|
||||
float* outMaxX, float* outMaxY) const {
|
||||
if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*outMinX = 0;
|
||||
*outMinY = 0;
|
||||
switch (mLocked.displayOrientation) {
|
||||
case DISPLAY_ORIENTATION_90:
|
||||
case DISPLAY_ORIENTATION_270:
|
||||
*outMaxX = mLocked.displayHeight - 1;
|
||||
*outMaxY = mLocked.displayWidth - 1;
|
||||
break;
|
||||
default:
|
||||
*outMaxX = mLocked.displayWidth - 1;
|
||||
*outMaxY = mLocked.displayHeight - 1;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PointerController::move(float deltaX, float deltaY) {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
|
||||
#endif
|
||||
if (deltaX == 0.0f && deltaY == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
|
||||
}
|
||||
|
||||
void PointerController::setButtonState(int32_t buttonState) {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("Set button state 0x%08x", buttonState);
|
||||
#endif
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.buttonState != buttonState) {
|
||||
mLocked.buttonState = buttonState;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t PointerController::getButtonState() const {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
return mLocked.buttonState;
|
||||
}
|
||||
|
||||
void PointerController::setPosition(float x, float y) {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
|
||||
#endif
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
setPositionLocked(x, y);
|
||||
}
|
||||
|
||||
void PointerController::setPositionLocked(float x, float y) {
|
||||
float minX, minY, maxX, maxY;
|
||||
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
|
||||
if (x <= minX) {
|
||||
mLocked.pointerX = minX;
|
||||
} else if (x >= maxX) {
|
||||
mLocked.pointerX = maxX;
|
||||
} else {
|
||||
mLocked.pointerX = x;
|
||||
}
|
||||
if (y <= minY) {
|
||||
mLocked.pointerY = minY;
|
||||
} else if (y >= maxY) {
|
||||
mLocked.pointerY = maxY;
|
||||
} else {
|
||||
mLocked.pointerY = y;
|
||||
}
|
||||
updatePointerLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::getPosition(float* outX, float* outY) const {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
*outX = mLocked.pointerX;
|
||||
*outY = mLocked.pointerY;
|
||||
}
|
||||
|
||||
void PointerController::fade(Transition transition) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
// Remove the inactivity timeout, since we are fading now.
|
||||
removeInactivityTimeoutLocked();
|
||||
|
||||
// Start fading.
|
||||
if (transition == TRANSITION_IMMEDIATE) {
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
mLocked.pointerAlpha = 0.0f;
|
||||
updatePointerLocked();
|
||||
} else {
|
||||
mLocked.pointerFadeDirection = -1;
|
||||
startAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::unfade(Transition transition) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
// Always reset the inactivity timer.
|
||||
resetInactivityTimeoutLocked();
|
||||
|
||||
// Start unfading.
|
||||
if (transition == TRANSITION_IMMEDIATE) {
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
mLocked.pointerAlpha = 1.0f;
|
||||
updatePointerLocked();
|
||||
} else {
|
||||
mLocked.pointerFadeDirection = 1;
|
||||
startAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setPresentation(Presentation presentation) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.presentation != presentation) {
|
||||
mLocked.presentation = presentation;
|
||||
mLocked.presentationChanged = true;
|
||||
|
||||
if (presentation != PRESENTATION_SPOT) {
|
||||
fadeOutAndReleaseAllSpotsLocked();
|
||||
}
|
||||
|
||||
updatePointerLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setSpots(const PointerCoords* spotCoords,
|
||||
const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("setSpots: idBits=%08x", spotIdBits.value);
|
||||
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
|
||||
uint32_t id = idBits.firstMarkedBit();
|
||||
idBits.clearBit(id);
|
||||
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
|
||||
ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
|
||||
c.getAxisValue(AMOTION_EVENT_AXIS_X),
|
||||
c.getAxisValue(AMOTION_EVENT_AXIS_Y),
|
||||
c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
|
||||
}
|
||||
#endif
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mSpriteController->openTransaction();
|
||||
|
||||
// Add or move spots for fingers that are down.
|
||||
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
|
||||
uint32_t id = idBits.clearFirstMarkedBit();
|
||||
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
|
||||
const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
|
||||
? mResources.spotTouch : mResources.spotHover;
|
||||
float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
|
||||
float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
|
||||
|
||||
Spot* spot = getSpotLocked(id);
|
||||
if (!spot) {
|
||||
spot = createAndAddSpotLocked(id);
|
||||
}
|
||||
|
||||
spot->updateSprite(&icon, x, y);
|
||||
}
|
||||
|
||||
// Remove spots for fingers that went up.
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
if (spot->id != Spot::INVALID_ID
|
||||
&& !spotIdBits.hasBit(spot->id)) {
|
||||
fadeOutAndReleaseSpotLocked(spot);
|
||||
}
|
||||
}
|
||||
|
||||
mSpriteController->closeTransaction();
|
||||
}
|
||||
|
||||
void PointerController::clearSpots() {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("clearSpots");
|
||||
#endif
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
fadeOutAndReleaseAllSpotsLocked();
|
||||
}
|
||||
|
||||
void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.inactivityTimeout != inactivityTimeout) {
|
||||
mLocked.inactivityTimeout = inactivityTimeout;
|
||||
resetInactivityTimeoutLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setDisplaySize(int32_t width, int32_t height) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
|
||||
mLocked.displayWidth = width;
|
||||
mLocked.displayHeight = height;
|
||||
|
||||
float minX, minY, maxX, maxY;
|
||||
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
|
||||
mLocked.pointerX = (minX + maxX) * 0.5f;
|
||||
mLocked.pointerY = (minY + maxY) * 0.5f;
|
||||
} else {
|
||||
mLocked.pointerX = 0;
|
||||
mLocked.pointerY = 0;
|
||||
}
|
||||
|
||||
fadeOutAndReleaseAllSpotsLocked();
|
||||
updatePointerLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setDisplayOrientation(int32_t orientation) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.displayOrientation != orientation) {
|
||||
// Apply offsets to convert from the pixel top-left corner position to the pixel center.
|
||||
// This creates an invariant frame of reference that we can easily rotate when
|
||||
// taking into account that the pointer may be located at fractional pixel offsets.
|
||||
float x = mLocked.pointerX + 0.5f;
|
||||
float y = mLocked.pointerY + 0.5f;
|
||||
float temp;
|
||||
|
||||
// Undo the previous rotation.
|
||||
switch (mLocked.displayOrientation) {
|
||||
case DISPLAY_ORIENTATION_90:
|
||||
temp = x;
|
||||
x = mLocked.displayWidth - y;
|
||||
y = temp;
|
||||
break;
|
||||
case DISPLAY_ORIENTATION_180:
|
||||
x = mLocked.displayWidth - x;
|
||||
y = mLocked.displayHeight - y;
|
||||
break;
|
||||
case DISPLAY_ORIENTATION_270:
|
||||
temp = x;
|
||||
x = y;
|
||||
y = mLocked.displayHeight - temp;
|
||||
break;
|
||||
}
|
||||
|
||||
// Perform the new rotation.
|
||||
switch (orientation) {
|
||||
case DISPLAY_ORIENTATION_90:
|
||||
temp = x;
|
||||
x = y;
|
||||
y = mLocked.displayWidth - temp;
|
||||
break;
|
||||
case DISPLAY_ORIENTATION_180:
|
||||
x = mLocked.displayWidth - x;
|
||||
y = mLocked.displayHeight - y;
|
||||
break;
|
||||
case DISPLAY_ORIENTATION_270:
|
||||
temp = x;
|
||||
x = mLocked.displayHeight - y;
|
||||
y = temp;
|
||||
break;
|
||||
}
|
||||
|
||||
// Apply offsets to convert from the pixel center to the pixel top-left corner position
|
||||
// and save the results.
|
||||
mLocked.pointerX = x - 0.5f;
|
||||
mLocked.pointerY = y - 0.5f;
|
||||
mLocked.displayOrientation = orientation;
|
||||
|
||||
updatePointerLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setPointerIcon(const SpriteIcon& icon) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mLocked.pointerIcon = icon.copy();
|
||||
mLocked.pointerIconChanged = true;
|
||||
|
||||
updatePointerLocked();
|
||||
}
|
||||
|
||||
void PointerController::handleMessage(const Message& message) {
|
||||
switch (message.what) {
|
||||
case MSG_ANIMATE:
|
||||
doAnimate();
|
||||
break;
|
||||
case MSG_INACTIVITY_TIMEOUT:
|
||||
doInactivityTimeout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::doAnimate() {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
bool keepAnimating = false;
|
||||
mLocked.animationPending = false;
|
||||
nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime;
|
||||
|
||||
// Animate pointer fade.
|
||||
if (mLocked.pointerFadeDirection < 0) {
|
||||
mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
|
||||
if (mLocked.pointerAlpha <= 0.0f) {
|
||||
mLocked.pointerAlpha = 0.0f;
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
} else {
|
||||
keepAnimating = true;
|
||||
}
|
||||
updatePointerLocked();
|
||||
} else if (mLocked.pointerFadeDirection > 0) {
|
||||
mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
|
||||
if (mLocked.pointerAlpha >= 1.0f) {
|
||||
mLocked.pointerAlpha = 1.0f;
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
} else {
|
||||
keepAnimating = true;
|
||||
}
|
||||
updatePointerLocked();
|
||||
}
|
||||
|
||||
// Animate spots that are fading out and being removed.
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
if (spot->id == Spot::INVALID_ID) {
|
||||
spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
|
||||
if (spot->alpha <= 0) {
|
||||
mLocked.spots.removeAt(i--);
|
||||
releaseSpotLocked(spot);
|
||||
} else {
|
||||
spot->sprite->setAlpha(spot->alpha);
|
||||
keepAnimating = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keepAnimating) {
|
||||
startAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::doInactivityTimeout() {
|
||||
fade(TRANSITION_GRADUAL);
|
||||
}
|
||||
|
||||
void PointerController::startAnimationLocked() {
|
||||
if (!mLocked.animationPending) {
|
||||
mLocked.animationPending = true;
|
||||
mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE));
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::resetInactivityTimeoutLocked() {
|
||||
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
|
||||
|
||||
nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT
|
||||
? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
|
||||
mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
|
||||
}
|
||||
|
||||
void PointerController::removeInactivityTimeoutLocked() {
|
||||
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
|
||||
}
|
||||
|
||||
void PointerController::updatePointerLocked() {
|
||||
mSpriteController->openTransaction();
|
||||
|
||||
mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
|
||||
mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
|
||||
|
||||
if (mLocked.pointerAlpha > 0) {
|
||||
mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
|
||||
mLocked.pointerSprite->setVisible(true);
|
||||
} else {
|
||||
mLocked.pointerSprite->setVisible(false);
|
||||
}
|
||||
|
||||
if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
|
||||
mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER
|
||||
? mLocked.pointerIcon : mResources.spotAnchor);
|
||||
mLocked.pointerIconChanged = false;
|
||||
mLocked.presentationChanged = false;
|
||||
}
|
||||
|
||||
mSpriteController->closeTransaction();
|
||||
}
|
||||
|
||||
PointerController::Spot* PointerController::getSpotLocked(uint32_t id) {
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
if (spot->id == id) {
|
||||
return spot;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) {
|
||||
// Remove spots until we have fewer than MAX_SPOTS remaining.
|
||||
while (mLocked.spots.size() >= MAX_SPOTS) {
|
||||
Spot* spot = removeFirstFadingSpotLocked();
|
||||
if (!spot) {
|
||||
spot = mLocked.spots.itemAt(0);
|
||||
mLocked.spots.removeAt(0);
|
||||
}
|
||||
releaseSpotLocked(spot);
|
||||
}
|
||||
|
||||
// Obtain a sprite from the recycled pool.
|
||||
sp<Sprite> sprite;
|
||||
if (! mLocked.recycledSprites.isEmpty()) {
|
||||
sprite = mLocked.recycledSprites.top();
|
||||
mLocked.recycledSprites.pop();
|
||||
} else {
|
||||
sprite = mSpriteController->createSprite();
|
||||
}
|
||||
|
||||
// Return the new spot.
|
||||
Spot* spot = new Spot(id, sprite);
|
||||
mLocked.spots.push(spot);
|
||||
return spot;
|
||||
}
|
||||
|
||||
PointerController::Spot* PointerController::removeFirstFadingSpotLocked() {
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
if (spot->id == Spot::INVALID_ID) {
|
||||
mLocked.spots.removeAt(i);
|
||||
return spot;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PointerController::releaseSpotLocked(Spot* spot) {
|
||||
spot->sprite->clearIcon();
|
||||
|
||||
if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
|
||||
mLocked.recycledSprites.push(spot->sprite);
|
||||
}
|
||||
|
||||
delete spot;
|
||||
}
|
||||
|
||||
void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
|
||||
if (spot->id != Spot::INVALID_ID) {
|
||||
spot->id = Spot::INVALID_ID;
|
||||
startAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::fadeOutAndReleaseAllSpotsLocked() {
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
fadeOutAndReleaseSpotLocked(spot);
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::loadResources() {
|
||||
mPolicy->loadPointerResources(&mResources);
|
||||
}
|
||||
|
||||
|
||||
// --- PointerController::Spot ---
|
||||
|
||||
void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) {
|
||||
sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
|
||||
sprite->setAlpha(alpha);
|
||||
sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
|
||||
sprite->setPosition(x, y);
|
||||
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
|
||||
if (icon != lastIcon) {
|
||||
lastIcon = icon;
|
||||
if (icon) {
|
||||
sprite->setIcon(*icon);
|
||||
sprite->setVisible(true);
|
||||
} else {
|
||||
sprite->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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_POINTER_CONTROLLER_H
|
||||
#define _UI_POINTER_CONTROLLER_H
|
||||
|
||||
#include "SpriteController.h"
|
||||
|
||||
#include "DisplayInfo.h"
|
||||
#include "Input.h"
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Looper.h>
|
||||
#include "String8.h"
|
||||
|
||||
#include <SkBitmap.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* Interface for tracking a mouse / touch pad pointer and touch pad spots.
|
||||
*
|
||||
* The spots are sprites on screen that visually represent the positions of
|
||||
* fingers
|
||||
*
|
||||
* The pointer controller is responsible for providing synchronization and for tracking
|
||||
* display orientation changes if needed.
|
||||
*/
|
||||
class PointerControllerInterface : public virtual RefBase {
|
||||
protected:
|
||||
PointerControllerInterface() { }
|
||||
virtual ~PointerControllerInterface() { }
|
||||
|
||||
public:
|
||||
/* Gets the bounds of the region that the pointer can traverse.
|
||||
* Returns true if the bounds are available. */
|
||||
virtual bool getBounds(float* outMinX, float* outMinY,
|
||||
float* outMaxX, float* outMaxY) const = 0;
|
||||
|
||||
/* Move the pointer. */
|
||||
virtual void move(float deltaX, float deltaY) = 0;
|
||||
|
||||
/* Sets a mask that indicates which buttons are pressed. */
|
||||
virtual void setButtonState(int32_t buttonState) = 0;
|
||||
|
||||
/* Gets a mask that indicates which buttons are pressed. */
|
||||
virtual int32_t getButtonState() const = 0;
|
||||
|
||||
/* Sets the absolute location of the pointer. */
|
||||
virtual void setPosition(float x, float y) = 0;
|
||||
|
||||
/* Gets the absolute location of the pointer. */
|
||||
virtual void getPosition(float* outX, float* outY) const = 0;
|
||||
|
||||
enum Transition {
|
||||
// Fade/unfade immediately.
|
||||
TRANSITION_IMMEDIATE,
|
||||
// Fade/unfade gradually.
|
||||
TRANSITION_GRADUAL,
|
||||
};
|
||||
|
||||
/* Fades the pointer out now. */
|
||||
virtual void fade(Transition transition) = 0;
|
||||
|
||||
/* Makes the pointer visible if it has faded out.
|
||||
* The pointer never unfades itself automatically. This method must be called
|
||||
* by the client whenever the pointer is moved or a button is pressed and it
|
||||
* wants to ensure that the pointer becomes visible again. */
|
||||
virtual void unfade(Transition transition) = 0;
|
||||
|
||||
enum Presentation {
|
||||
// Show the mouse pointer.
|
||||
PRESENTATION_POINTER,
|
||||
// Show spots and a spot anchor in place of the mouse pointer.
|
||||
PRESENTATION_SPOT,
|
||||
};
|
||||
|
||||
/* Sets the mode of the pointer controller. */
|
||||
virtual void setPresentation(Presentation presentation) = 0;
|
||||
|
||||
/* Sets the spots for the current gesture.
|
||||
* The spots are not subject to the inactivity timeout like the pointer
|
||||
* itself it since they are expected to remain visible for so long as
|
||||
* the fingers are on the touch pad.
|
||||
*
|
||||
* The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant.
|
||||
* For spotCoords, pressure != 0 indicates that the spot's location is being
|
||||
* pressed (not hovering).
|
||||
*/
|
||||
virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
|
||||
BitSet32 spotIdBits) = 0;
|
||||
|
||||
/* Removes all spots. */
|
||||
virtual void clearSpots() = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Pointer resources.
|
||||
*/
|
||||
struct PointerResources {
|
||||
SpriteIcon spotHover;
|
||||
SpriteIcon spotTouch;
|
||||
SpriteIcon spotAnchor;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Pointer controller policy interface.
|
||||
*
|
||||
* The pointer controller policy is used by the pointer controller to interact with
|
||||
* the Window Manager and other system components.
|
||||
*
|
||||
* The actual implementation is partially supported by callbacks into the DVM
|
||||
* via JNI. This interface is also mocked in the unit tests.
|
||||
*/
|
||||
class PointerControllerPolicyInterface : public virtual RefBase {
|
||||
protected:
|
||||
PointerControllerPolicyInterface() { }
|
||||
virtual ~PointerControllerPolicyInterface() { }
|
||||
|
||||
public:
|
||||
virtual void loadPointerResources(PointerResources* outResources) = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Tracks pointer movements and draws the pointer sprite to a surface.
|
||||
*
|
||||
* Handles pointer acceleration and animation.
|
||||
*/
|
||||
class PointerController : public PointerControllerInterface, public MessageHandler {
|
||||
protected:
|
||||
virtual ~PointerController();
|
||||
|
||||
public:
|
||||
enum InactivityTimeout {
|
||||
INACTIVITY_TIMEOUT_NORMAL = 0,
|
||||
INACTIVITY_TIMEOUT_SHORT = 1,
|
||||
};
|
||||
|
||||
PointerController(const sp<PointerControllerPolicyInterface>& policy,
|
||||
const sp<Looper>& looper, const sp<SpriteController>& spriteController);
|
||||
|
||||
virtual bool getBounds(float* outMinX, float* outMinY,
|
||||
float* outMaxX, float* outMaxY) const;
|
||||
virtual void move(float deltaX, float deltaY);
|
||||
virtual void setButtonState(int32_t buttonState);
|
||||
virtual int32_t getButtonState() const;
|
||||
virtual void setPosition(float x, float y);
|
||||
virtual void getPosition(float* outX, float* outY) const;
|
||||
virtual void fade(Transition transition);
|
||||
virtual void unfade(Transition transition);
|
||||
|
||||
virtual void setPresentation(Presentation presentation);
|
||||
virtual void setSpots(const PointerCoords* spotCoords,
|
||||
const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
|
||||
virtual void clearSpots();
|
||||
|
||||
void setDisplaySize(int32_t width, int32_t height);
|
||||
void setDisplayOrientation(int32_t orientation);
|
||||
void setPointerIcon(const SpriteIcon& icon);
|
||||
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
|
||||
|
||||
private:
|
||||
static const size_t MAX_RECYCLED_SPRITES = 12;
|
||||
static const size_t MAX_SPOTS = 12;
|
||||
|
||||
enum {
|
||||
MSG_ANIMATE,
|
||||
MSG_INACTIVITY_TIMEOUT,
|
||||
};
|
||||
|
||||
struct Spot {
|
||||
static const uint32_t INVALID_ID = 0xffffffff;
|
||||
|
||||
uint32_t id;
|
||||
sp<Sprite> sprite;
|
||||
float alpha;
|
||||
float scale;
|
||||
float x, y;
|
||||
|
||||
inline Spot(uint32_t id, const sp<Sprite>& sprite)
|
||||
: id(id), sprite(sprite), alpha(1.0f), scale(1.0f),
|
||||
x(0.0f), y(0.0f), lastIcon(NULL) { }
|
||||
|
||||
void updateSprite(const SpriteIcon* icon, float x, float y);
|
||||
|
||||
private:
|
||||
const SpriteIcon* lastIcon;
|
||||
};
|
||||
|
||||
mutable Mutex mLock;
|
||||
|
||||
sp<PointerControllerPolicyInterface> mPolicy;
|
||||
sp<Looper> mLooper;
|
||||
sp<SpriteController> mSpriteController;
|
||||
sp<WeakMessageHandler> mHandler;
|
||||
|
||||
PointerResources mResources;
|
||||
|
||||
struct Locked {
|
||||
bool animationPending;
|
||||
nsecs_t animationTime;
|
||||
|
||||
int32_t displayWidth;
|
||||
int32_t displayHeight;
|
||||
int32_t displayOrientation;
|
||||
|
||||
InactivityTimeout inactivityTimeout;
|
||||
|
||||
Presentation presentation;
|
||||
bool presentationChanged;
|
||||
|
||||
int32_t pointerFadeDirection;
|
||||
float pointerX;
|
||||
float pointerY;
|
||||
float pointerAlpha;
|
||||
sp<Sprite> pointerSprite;
|
||||
SpriteIcon pointerIcon;
|
||||
bool pointerIconChanged;
|
||||
|
||||
int32_t buttonState;
|
||||
|
||||
Vector<Spot*> spots;
|
||||
Vector<sp<Sprite> > recycledSprites;
|
||||
} mLocked;
|
||||
|
||||
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
|
||||
void setPositionLocked(float x, float y);
|
||||
|
||||
void handleMessage(const Message& message);
|
||||
void doAnimate();
|
||||
void doInactivityTimeout();
|
||||
|
||||
void startAnimationLocked();
|
||||
|
||||
void resetInactivityTimeoutLocked();
|
||||
void removeInactivityTimeoutLocked();
|
||||
void updatePointerLocked();
|
||||
|
||||
Spot* getSpotLocked(uint32_t id);
|
||||
Spot* createAndAddSpotLocked(uint32_t id);
|
||||
Spot* removeFirstFadingSpotLocked();
|
||||
void releaseSpotLocked(Spot* spot);
|
||||
void fadeOutAndReleaseSpotLocked(Spot* spot);
|
||||
void fadeOutAndReleaseAllSpotsLocked();
|
||||
|
||||
void loadResources();
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_POINTER_CONTROLLER_H
|
|
@ -0,0 +1,509 @@
|
|||
/*
|
||||
* 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 "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);
|
||||
|
||||
mLocked.transactionNestingCount = 0;
|
||||
mLocked.deferredSpriteUpdate = false;
|
||||
}
|
||||
|
||||
SpriteController::~SpriteController() {
|
||||
mLooper->removeMessages(mHandler);
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
if (mSurfaceComposerClient != NULL) {
|
||||
mSurfaceComposerClient->dispose();
|
||||
mSurfaceComposerClient.clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sp<Sprite> SpriteController::createSprite() {
|
||||
return new SpriteImpl(this);
|
||||
}
|
||||
|
||||
void SpriteController::openTransaction() {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mLocked.transactionNestingCount += 1;
|
||||
}
|
||||
|
||||
void SpriteController::closeTransaction() {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0,
|
||||
"Sprite closeTransaction() called but there is no open sprite transaction");
|
||||
|
||||
mLocked.transactionNestingCount -= 1;
|
||||
if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) {
|
||||
mLocked.deferredSpriteUpdate = false;
|
||||
mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
|
||||
bool wasEmpty = mLocked.invalidatedSprites.isEmpty();
|
||||
mLocked.invalidatedSprites.push(sprite);
|
||||
if (wasEmpty) {
|
||||
if (mLocked.transactionNestingCount != 0) {
|
||||
mLocked.deferredSpriteUpdate = true;
|
||||
} else {
|
||||
mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) {
|
||||
bool wasEmpty = mLocked.disposedSurfaces.isEmpty();
|
||||
mLocked.disposedSurfaces.push(surfaceControl);
|
||||
if (wasEmpty) {
|
||||
mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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 = mLocked.invalidatedSprites.size();
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i);
|
||||
|
||||
updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
|
||||
sprite->resetDirtyLocked();
|
||||
}
|
||||
mLocked.invalidatedSprites.clear();
|
||||
} // release lock
|
||||
|
||||
// Create missing surfaces.
|
||||
bool surfaceChanged = false;
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
SpriteUpdate& update = updates.editItemAt(i);
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {
|
||||
update.state.surfaceWidth = update.state.icon.bitmap.width();
|
||||
update.state.surfaceHeight = update.state.icon.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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Resize sprites if needed, inside a global transaction.
|
||||
bool haveGlobalTransaction = false;
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
SpriteUpdate& update = updates.editItemAt(i);
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
|
||||
int32_t desiredWidth = update.state.icon.bitmap.width();
|
||||
int32_t desiredHeight = update.state.icon.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) {
|
||||
ALOGE("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) {
|
||||
ALOGE("Error %d hiding sprite surface after resize.", status);
|
||||
} else {
|
||||
update.state.surfaceVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
if (haveGlobalTransaction) {
|
||||
SurfaceComposerClient::closeGlobalTransaction();
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
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) {
|
||||
ALOGE("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.icon.bitmap, 0, 0, &paint);
|
||||
|
||||
if (surfaceInfo.w > uint32_t(update.state.icon.bitmap.width())) {
|
||||
paint.setColor(0); // transparent fill color
|
||||
surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0,
|
||||
surfaceInfo.w, update.state.icon.bitmap.height(), paint);
|
||||
}
|
||||
if (surfaceInfo.h > uint32_t(update.state.icon.bitmap.height())) {
|
||||
paint.setColor(0); // transparent fill color
|
||||
surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(),
|
||||
surfaceInfo.w, surfaceInfo.h, paint);
|
||||
}
|
||||
|
||||
status = surface->unlockAndPost();
|
||||
if (status) {
|
||||
ALOGE("Error %d unlocking and posting sprite surface after drawing.", status);
|
||||
} else {
|
||||
update.state.surfaceDrawn = true;
|
||||
update.surfaceChanged = surfaceChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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;
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
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) {
|
||||
SurfaceComposerClient::openGlobalTransaction();
|
||||
haveTransaction = true;
|
||||
}
|
||||
|
||||
if (wantSurfaceVisibleAndDrawn
|
||||
&& (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
|
||||
status = update.state.surfaceControl->setAlpha(update.state.alpha);
|
||||
if (status) {
|
||||
ALOGE("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.icon.hotSpotX,
|
||||
update.state.positionY - update.state.icon.hotSpotY);
|
||||
if (status) {
|
||||
ALOGE("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) {
|
||||
ALOGE("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) {
|
||||
ALOGE("Error %d setting sprite surface layer.", status);
|
||||
}
|
||||
}
|
||||
|
||||
if (becomingVisible) {
|
||||
status = update.state.surfaceControl->show(surfaceLayer);
|
||||
if (status) {
|
||||
ALOGE("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) {
|
||||
ALOGE("Error %d hiding sprite surface.", status);
|
||||
} else {
|
||||
update.state.surfaceVisible = false;
|
||||
update.surfaceChanged = surfaceChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
if (haveTransaction) {
|
||||
SurfaceComposerClient::closeGlobalTransaction();
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
if (update.surfaceChanged) {
|
||||
update.sprite->setSurfaceLocked(update.state.surfaceControl,
|
||||
update.state.surfaceWidth, update.state.surfaceHeight,
|
||||
update.state.surfaceDrawn, update.state.surfaceVisible);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} // 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() {
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
// Collect disposed surfaces.
|
||||
Vector<sp<SurfaceControl> > disposedSurfaces;
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
disposedSurfaces = mLocked.disposedSurfaces;
|
||||
mLocked.disposedSurfaces.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();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpriteController::ensureSurfaceComposerClient() {
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
if (mSurfaceComposerClient == NULL) {
|
||||
mSurfaceComposerClient = new SurfaceComposerClient();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
|
||||
ensureSurfaceComposerClient();
|
||||
|
||||
sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
|
||||
String8("Sprite"), 0, width, height, PIXEL_FORMAT_RGBA_8888);
|
||||
if (surfaceControl == NULL || !surfaceControl->isValid()
|
||||
|| !surfaceControl->getSurface()->isValid()) {
|
||||
ALOGE("Error creating sprite surface.");
|
||||
return NULL;
|
||||
}
|
||||
return surfaceControl;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// --- SpriteController::SpriteImpl ---
|
||||
|
||||
SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
|
||||
mController(controller) {
|
||||
}
|
||||
|
||||
SpriteController::SpriteImpl::~SpriteImpl() {
|
||||
AutoMutex _m(mController->mLock);
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
// 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 (mLocked.state.surfaceControl != NULL) {
|
||||
mController->disposeSurfaceLocked(mLocked.state.surfaceControl);
|
||||
mLocked.state.surfaceControl.clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
uint32_t dirty;
|
||||
if (icon.isValid()) {
|
||||
icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config);
|
||||
|
||||
if (!mLocked.state.icon.isValid()
|
||||
|| mLocked.state.icon.hotSpotX != icon.hotSpotX
|
||||
|| mLocked.state.icon.hotSpotY != icon.hotSpotY) {
|
||||
mLocked.state.icon.hotSpotX = icon.hotSpotX;
|
||||
mLocked.state.icon.hotSpotY = icon.hotSpotY;
|
||||
dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
|
||||
} else {
|
||||
dirty = DIRTY_BITMAP;
|
||||
}
|
||||
} else if (mLocked.state.icon.isValid()) {
|
||||
mLocked.state.icon.bitmap.reset();
|
||||
dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
|
||||
} else {
|
||||
return; // setting to invalid icon and already invalid so nothing to do
|
||||
}
|
||||
|
||||
invalidateLocked(dirty);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setVisible(bool visible) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.visible != visible) {
|
||||
mLocked.state.visible = visible;
|
||||
invalidateLocked(DIRTY_VISIBILITY);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setPosition(float x, float y) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.positionX != x || mLocked.state.positionY != y) {
|
||||
mLocked.state.positionX = x;
|
||||
mLocked.state.positionY = y;
|
||||
invalidateLocked(DIRTY_POSITION);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setLayer(int32_t layer) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.layer != layer) {
|
||||
mLocked.state.layer = layer;
|
||||
invalidateLocked(DIRTY_LAYER);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setAlpha(float alpha) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.alpha != alpha) {
|
||||
mLocked.state.alpha = alpha;
|
||||
invalidateLocked(DIRTY_ALPHA);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setTransformationMatrix(
|
||||
const SpriteTransformationMatrix& matrix) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.transformationMatrix != matrix) {
|
||||
mLocked.state.transformationMatrix = matrix;
|
||||
invalidateLocked(DIRTY_TRANSFORMATION_MATRIX);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
|
||||
bool wasDirty = mLocked.state.dirty;
|
||||
mLocked.state.dirty |= dirty;
|
||||
|
||||
if (!wasDirty) {
|
||||
mController->invalidateSpriteLocked(this);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
#include <surfaceflinger/Surface.h>
|
||||
#include <surfaceflinger/SurfaceComposerClient.h>
|
||||
#include <surfaceflinger/ISurfaceComposer.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Transformation matrix for a sprite.
|
||||
*/
|
||||
struct SpriteTransformationMatrix {
|
||||
inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { }
|
||||
inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) :
|
||||
dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { }
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Icon that a sprite displays, including its hotspot.
|
||||
*/
|
||||
struct SpriteIcon {
|
||||
inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { }
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) :
|
||||
bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
|
||||
|
||||
SkBitmap bitmap;
|
||||
#endif
|
||||
float hotSpotX;
|
||||
float hotSpotY;
|
||||
|
||||
inline SpriteIcon copy() const {
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
SkBitmap bitmapCopy;
|
||||
bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config);
|
||||
return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY);
|
||||
#else
|
||||
return SpriteIcon();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void reset() {
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
bitmap.reset();
|
||||
hotSpotX = 0;
|
||||
hotSpotY = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool isValid() const {
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
return !bitmap.isNull() && !bitmap.empty();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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:
|
||||
enum {
|
||||
// The base layer for pointer sprites.
|
||||
BASE_LAYER_POINTER = 0, // reserve space for 1 pointer
|
||||
|
||||
// The base layer for spot sprites.
|
||||
BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots
|
||||
};
|
||||
|
||||
/* Sets the bitmap that is drawn by the sprite.
|
||||
* The sprite retains a copy of the bitmap for subsequent rendering. */
|
||||
virtual void setIcon(const SpriteIcon& icon) = 0;
|
||||
|
||||
inline void clearIcon() {
|
||||
setIcon(SpriteIcon());
|
||||
}
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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();
|
||||
|
||||
/* 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(). */
|
||||
void openTransaction();
|
||||
void closeTransaction();
|
||||
|
||||
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), visible(false),
|
||||
positionX(0), positionY(0), layer(0), alpha(1.0f),
|
||||
surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
|
||||
}
|
||||
|
||||
uint32_t dirty;
|
||||
|
||||
SpriteIcon icon;
|
||||
bool visible;
|
||||
float positionX;
|
||||
float positionY;
|
||||
int32_t layer;
|
||||
float alpha;
|
||||
SpriteTransformationMatrix transformationMatrix;
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
sp<SurfaceControl> surfaceControl;
|
||||
#endif
|
||||
int32_t surfaceWidth;
|
||||
int32_t surfaceHeight;
|
||||
bool surfaceDrawn;
|
||||
bool surfaceVisible;
|
||||
|
||||
inline bool wantSurfaceVisible() const {
|
||||
return visible && alpha > 0.0f && icon.isValid();
|
||||
}
|
||||
};
|
||||
|
||||
/* 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 setIcon(const SpriteIcon& icon);
|
||||
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);
|
||||
|
||||
inline const SpriteState& getStateLocked() const {
|
||||
return mLocked.state;
|
||||
}
|
||||
|
||||
inline void resetDirtyLocked() {
|
||||
mLocked.state.dirty = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl,
|
||||
int32_t width, int32_t height, bool drawn, bool visible) {
|
||||
mLocked.state.surfaceControl = surfaceControl;
|
||||
mLocked.state.surfaceWidth = width;
|
||||
mLocked.state.surfaceHeight = height;
|
||||
mLocked.state.surfaceDrawn = drawn;
|
||||
mLocked.state.surfaceVisible = visible;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
sp<SpriteController> mController;
|
||||
|
||||
struct Locked {
|
||||
SpriteState state;
|
||||
} mLocked; // 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;
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
sp<SurfaceComposerClient> mSurfaceComposerClient;
|
||||
#endif
|
||||
|
||||
struct Locked {
|
||||
Vector<sp<SpriteImpl> > invalidatedSprites;
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
Vector<sp<SurfaceControl> > disposedSurfaces;
|
||||
#endif
|
||||
uint32_t transactionNestingCount;
|
||||
bool deferredSpriteUpdate;
|
||||
} mLocked; // guarded by mLock
|
||||
|
||||
void invalidateSpriteLocked(const sp<SpriteImpl>& sprite);
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl);
|
||||
#endif
|
||||
|
||||
void handleMessage(const Message& message);
|
||||
void doUpdateSprites();
|
||||
void doDisposeSurfaces();
|
||||
|
||||
void ensureSurfaceComposerClient();
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
sp<SurfaceControl> obtainSurface(int32_t width, int32_t height);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_SPRITES_H
|
|
@ -279,7 +279,8 @@ public:
|
|||
GeckoInputReaderPolicy() {}
|
||||
|
||||
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
|
||||
|
||||
virtual sp<PointerControllerInterface> obtainPointerController(int32_t
|
||||
deviceId) { return NULL; };
|
||||
void setDisplayInfo();
|
||||
|
||||
protected:
|
||||
|
|
Загрузка…
Ссылка в новой задаче