Switch to callback animation

Modified current animation logic to use callbacks from the controllers
to further clean and modularize code.
Test: Pixel 3XL device, atest PointerController_test, compile

Change-Id: I1073bd78687cca491663c0349751dab4b30aa8e2
This commit is contained in:
Liam Harrington
2020-08-14 04:00:11 +00:00
parent f623c1e2c2
commit ce63713955
8 changed files with 221 additions and 88 deletions

View File

@@ -168,7 +168,7 @@ void MouseCursorController::fade(PointerControllerInterface::Transition transiti
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = -1;
mContext.startAnimation();
startAnimationLocked();
}
}
@@ -185,7 +185,7 @@ void MouseCursorController::unfade(PointerControllerInterface::Transition transi
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = 1;
mContext.startAnimation();
startAnimationLocked();
}
}
@@ -312,10 +312,9 @@ void MouseCursorController::setCustomPointerIcon(const SpriteIcon& icon) {
updatePointerLocked();
}
bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) {
bool MouseCursorController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
nsecs_t frameDelay = timestamp - mContext.getAnimationTime();
std::scoped_lock lock(mLock);
bool keepAnimating = false;
// Animate pointer fade.
if (mLocked.pointerFadeDirection < 0) {
@@ -337,13 +336,10 @@ bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimat
}
updatePointerLocked();
}
return keepAnimating;
}
bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) {
std::scoped_lock lock(mLock);
bool MouseCursorController::doBitmapAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
std::map<int32_t, PointerAnimation>::const_iterator iter =
mLocked.animationResources.find(mLocked.requestedPointerType);
if (iter == mLocked.animationResources.end()) {
@@ -364,7 +360,6 @@ bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) {
spriteController->closeTransaction();
}
// Keep animating.
return true;
}
@@ -399,7 +394,7 @@ void MouseCursorController::updatePointerLocked() REQUIRES(mLock) {
if (anim_iter != mLocked.animationResources.end()) {
mLocked.animationFrameIndex = 0;
mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
mContext.startAnimation();
startAnimationLocked();
}
mLocked.pointerSprite->setIcon(iter->second);
} else {
@@ -457,4 +452,38 @@ bool MouseCursorController::resourcesLoaded() {
return mLocked.resourcesLoaded;
}
bool MouseCursorController::doAnimations(nsecs_t timestamp) {
std::scoped_lock lock(mLock);
bool keepFading = doFadingAnimationLocked(timestamp);
bool keepBitmap = doBitmapAnimationLocked(timestamp);
bool keepAnimating = keepFading || keepBitmap;
if (!keepAnimating) {
/*
* We know that this callback will be removed before another
* is added. mLock in PointerAnimator will not be released
* until after this is removed, and adding another callback
* requires that lock. Thus it's safe to set mLocked.animating
* here.
*/
mLocked.animating = false;
}
return keepAnimating;
}
void MouseCursorController::startAnimationLocked() REQUIRES(mLock) {
using namespace std::placeholders;
if (mLocked.animating) {
return;
}
mLocked.animating = true;
std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1);
/*
* Using -1 for displayId here to avoid removing the callback
* if a TouchSpotController with the same display is removed.
*/
mContext.addAnimationCallback(-1, func);
}
} // namespace android

View File

@@ -25,6 +25,7 @@
#include <utils/Looper.h>
#include <utils/RefBase.h>
#include <functional>
#include <map>
#include <memory>
#include <vector>
@@ -61,8 +62,7 @@ public:
void getAdditionalMouseResources();
bool isViewportValid();
bool doBitmapAnimation(nsecs_t timestamp);
bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating);
bool doAnimations(nsecs_t timestamp);
bool resourcesLoaded();
@@ -96,6 +96,8 @@ private:
int32_t buttonState;
bool animating{false};
} mLocked GUARDED_BY(mLock);
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
@@ -104,6 +106,11 @@ private:
void updatePointerLocked();
void loadResourcesLocked(bool getAdditionalMouseResources);
bool doBitmapAnimationLocked(nsecs_t timestamp);
bool doFadingAnimationLocked(nsecs_t timestamp);
void startAnimationLocked();
};
} // namespace android

View File

@@ -57,7 +57,6 @@ std::shared_ptr<PointerController> PointerController::create(
controller->mContext.setHandlerController(controller);
controller->mContext.setCallbackController(controller);
controller->mContext.initializeDisplayEventReceiver();
return controller;
}
@@ -189,24 +188,6 @@ void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
mCursorController.setCustomPointerIcon(icon);
}
void PointerController::doAnimate(nsecs_t timestamp) {
std::scoped_lock lock(mLock);
mContext.setAnimationPending(false);
bool keepFading = false;
keepFading = mCursorController.doFadingAnimation(timestamp, keepFading);
for (auto& [displayID, spotController] : mLocked.spotControllers) {
keepFading = spotController.doFadingAnimation(timestamp, keepFading);
}
bool keepBitmapFlipping = mCursorController.doBitmapAnimation(timestamp);
if (keepFading || keepBitmapFlipping) {
mContext.startAnimation();
}
}
void PointerController::doInactivityTimeout() {
fade(Transition::GRADUAL);
}
@@ -221,6 +202,11 @@ void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>&
for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) {
int32_t displayID = it->first;
if (!displayIdSet.count(displayID)) {
/*
* Ensures that an in-progress animation won't dereference
* a null pointer to TouchSpotController.
*/
mContext.removeAnimationCallback(displayID);
it = mLocked.spotControllers.erase(it);
} else {
++it;

View File

@@ -70,7 +70,6 @@ public:
void setCustomPointerIcon(const SpriteIcon& icon);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void doInactivityTimeout();
void doAnimate(nsecs_t timestamp);
void reloadPointerResources();
void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports);

View File

@@ -38,10 +38,10 @@ PointerControllerContext::PointerControllerContext(
mSpriteController(spriteController),
mHandler(new MessageHandler()),
mCallback(new LooperCallback()),
mController(controller) {
mController(controller),
mAnimator(*this) {
std::scoped_lock lock(mLock);
mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
mLocked.animationPending = false;
}
PointerControllerContext::~PointerControllerContext() {
@@ -57,15 +57,6 @@ void PointerControllerContext::setInactivityTimeout(InactivityTimeout inactivity
}
}
void PointerControllerContext::startAnimation() {
std::scoped_lock lock(mLock);
if (!mLocked.animationPending) {
mLocked.animationPending = true;
mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
mDisplayEventReceiver.requestNextVsync();
}
}
void PointerControllerContext::resetInactivityTimeout() {
std::scoped_lock lock(mLock);
resetInactivityTimeoutLocked();
@@ -85,14 +76,8 @@ void PointerControllerContext::removeInactivityTimeout() {
mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
}
void PointerControllerContext::setAnimationPending(bool animationPending) {
std::scoped_lock lock(mLock);
mLocked.animationPending = animationPending;
}
nsecs_t PointerControllerContext::getAnimationTime() {
std::scoped_lock lock(mLock);
return mLocked.animationTime;
nsecs_t PointerControllerContext::getAnimationTime() REQUIRES(mAnimator.mLock) {
return mAnimator.getAnimationTimeLocked();
}
void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) {
@@ -112,31 +97,8 @@ sp<SpriteController> PointerControllerContext::getSpriteController() {
return mSpriteController;
}
void PointerControllerContext::initializeDisplayEventReceiver() {
if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK, Looper::EVENT_INPUT,
mCallback, nullptr);
} else {
ALOGE("Failed to initialize DisplayEventReceiver.");
}
}
void PointerControllerContext::handleDisplayEvents() {
bool gotVsync = false;
ssize_t n;
nsecs_t timestamp;
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
timestamp = buf[i].header.timestamp;
gotVsync = true;
}
}
}
if (gotVsync) {
mController.doAnimate(timestamp);
}
mAnimator.handleVsyncEvents();
}
void PointerControllerContext::MessageHandler::handleMessage(const Message& message) {
@@ -176,4 +138,91 @@ int PointerControllerContext::LooperCallback::handleEvent(int /* fd */, int even
return 1; // keep the callback
}
void PointerControllerContext::addAnimationCallback(int32_t displayId,
std::function<bool(nsecs_t)> callback) {
mAnimator.addCallback(displayId, callback);
}
void PointerControllerContext::removeAnimationCallback(int32_t displayId) {
mAnimator.removeCallback(displayId);
}
PointerControllerContext::PointerAnimator::PointerAnimator(PointerControllerContext& context)
: mContext(context) {
initializeDisplayEventReceiver();
}
void PointerControllerContext::PointerAnimator::initializeDisplayEventReceiver() {
if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
mContext.mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
Looper::EVENT_INPUT, mContext.mCallback, nullptr);
} else {
ALOGE("Failed to initialize DisplayEventReceiver.");
}
}
void PointerControllerContext::PointerAnimator::addCallback(int32_t displayId,
std::function<bool(nsecs_t)> callback) {
std::scoped_lock lock(mLock);
mLocked.callbacks[displayId] = callback;
startAnimationLocked();
}
void PointerControllerContext::PointerAnimator::removeCallback(int32_t displayId) {
std::scoped_lock lock(mLock);
auto it = mLocked.callbacks.find(displayId);
if (it == mLocked.callbacks.end()) {
return;
}
mLocked.callbacks.erase(it);
}
void PointerControllerContext::PointerAnimator::handleVsyncEvents() {
bool gotVsync = false;
ssize_t n;
nsecs_t timestamp;
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
timestamp = buf[i].header.timestamp;
gotVsync = true;
}
}
}
if (gotVsync) {
std::scoped_lock lock(mLock);
mLocked.animationPending = false;
handleCallbacksLocked(timestamp);
}
}
nsecs_t PointerControllerContext::PointerAnimator::getAnimationTimeLocked() REQUIRES(mLock) {
return mLocked.animationTime;
}
void PointerControllerContext::PointerAnimator::startAnimationLocked() REQUIRES(mLock) {
if (!mLocked.animationPending) {
mLocked.animationPending = true;
mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
mDisplayEventReceiver.requestNextVsync();
}
}
void PointerControllerContext::PointerAnimator::handleCallbacksLocked(nsecs_t timestamp)
REQUIRES(mLock) {
for (auto it = mLocked.callbacks.begin(); it != mLocked.callbacks.end();) {
bool keepCallback = it->second(timestamp);
if (!keepCallback) {
it = mLocked.callbacks.erase(it);
} else {
++it;
}
}
if (!mLocked.callbacks.empty()) {
startAnimationLocked();
}
}
} // namespace android

View File

@@ -26,6 +26,7 @@
#include <utils/Looper.h>
#include <utils/RefBase.h>
#include <functional>
#include <map>
#include <memory>
#include <vector>
@@ -35,6 +36,8 @@
namespace android {
class PointerController;
class MouseCursorController;
class TouchSpotController;
/*
* Pointer resources.
@@ -96,7 +99,6 @@ public:
void startAnimation();
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void setAnimationPending(bool animationPending);
nsecs_t getAnimationTime();
void clearSpotsByDisplay(int32_t displayId);
@@ -107,9 +109,11 @@ public:
sp<PointerControllerPolicyInterface> getPolicy();
sp<SpriteController> getSpriteController();
void initializeDisplayEventReceiver();
void handleDisplayEvents();
void addAnimationCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
void removeAnimationCallback(int32_t displayId);
class MessageHandler : public virtual android::MessageHandler {
public:
enum {
@@ -127,22 +131,47 @@ public:
};
private:
class PointerAnimator {
public:
PointerAnimator(PointerControllerContext& context);
void addCallback(int32_t displayId, std::function<bool(nsecs_t)> callback);
void removeCallback(int32_t displayId);
void handleVsyncEvents();
nsecs_t getAnimationTimeLocked();
mutable std::mutex mLock;
private:
struct Locked {
bool animationPending{false};
nsecs_t animationTime{systemTime(SYSTEM_TIME_MONOTONIC)};
std::unordered_map<int32_t, std::function<bool(nsecs_t)>> callbacks;
} mLocked GUARDED_BY(mLock);
DisplayEventReceiver mDisplayEventReceiver;
PointerControllerContext& mContext;
void initializeDisplayEventReceiver();
void startAnimationLocked();
void handleCallbacksLocked(nsecs_t timestamp);
};
sp<PointerControllerPolicyInterface> mPolicy;
sp<Looper> mLooper;
sp<SpriteController> mSpriteController;
sp<MessageHandler> mHandler;
sp<LooperCallback> mCallback;
DisplayEventReceiver mDisplayEventReceiver;
PointerController& mController;
PointerAnimator mAnimator;
mutable std::mutex mLock;
struct Locked {
bool animationPending;
nsecs_t animationTime;
InactivityTimeout inactivityTimeout;
} mLocked GUARDED_BY(mLock);

View File

@@ -142,7 +142,8 @@ TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id,
}
TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id,
std::vector<Spot*>& spots) {
std::vector<Spot*>& spots)
REQUIRES(mLock) {
// Remove spots until we have fewer than MAX_SPOTS remaining.
while (spots.size() >= MAX_SPOTS) {
Spot* spot = removeFirstFadingSpotLocked(spots);
@@ -186,14 +187,13 @@ void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) {
if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
mLocked.recycledSprites.push_back(spot->sprite);
}
delete spot;
}
void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) {
if (spot->id != Spot::INVALID_ID) {
spot->id = Spot::INVALID_ID;
mContext.startAnimation();
startAnimationLocked();
}
}
@@ -209,8 +209,24 @@ void TouchSpotController::reloadSpotResources() {
mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
}
bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) {
bool TouchSpotController::doAnimations(nsecs_t timestamp) {
std::scoped_lock lock(mLock);
bool keepAnimating = doFadingAnimationLocked(timestamp);
if (!keepAnimating) {
/*
* We know that this callback will be removed before another
* is added. mLock in PointerAnimator will not be released
* until after this is removed, and adding another callback
* requires that lock. Thus it's safe to set mLocked.animating
* here.
*/
mLocked.animating = false;
}
return keepAnimating;
}
bool TouchSpotController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
bool keepAnimating = false;
nsecs_t animationTime = mContext.getAnimationTime();
nsecs_t frameDelay = timestamp - animationTime;
size_t numSpots = mLocked.displaySpots.size();
@@ -233,4 +249,16 @@ bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimatin
return keepAnimating;
}
void TouchSpotController::startAnimationLocked() REQUIRES(mLock) {
using namespace std::placeholders;
if (mLocked.animating) {
return;
}
mLocked.animating = true;
std::function<bool(nsecs_t)> func = std::bind(&TouchSpotController::doAnimations, this, _1);
mContext.addAnimationCallback(mDisplayId, func);
}
} // namespace android

View File

@@ -17,6 +17,8 @@
#ifndef _UI_TOUCH_SPOT_CONTROLLER_H
#define _UI_TOUCH_SPOT_CONTROLLER_H
#include <functional>
#include "PointerControllerContext.h"
namespace android {
@@ -34,7 +36,7 @@ public:
void clearSpots();
void reloadSpotResources();
bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating);
bool doAnimations(nsecs_t timestamp);
private:
struct Spot {
@@ -76,6 +78,8 @@ private:
std::vector<Spot*> displaySpots;
std::vector<sp<Sprite>> recycledSprites;
bool animating{false};
} mLocked GUARDED_BY(mLock);
Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots);
@@ -84,6 +88,8 @@ private:
void releaseSpotLocked(Spot* spot);
void fadeOutAndReleaseSpotLocked(Spot* spot);
void fadeOutAndReleaseAllSpotsLocked();
bool doFadingAnimationLocked(nsecs_t timestamp);
void startAnimationLocked();
};
} // namespace android