229 lines
7.8 KiB
C++
229 lines
7.8 KiB
C++
/*
|
|
* Copyright (C) 2020 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.
|
|
*/
|
|
|
|
#include "PointerControllerContext.h"
|
|
#include "PointerController.h"
|
|
|
|
namespace {
|
|
// Time to wait before starting the fade when the pointer is inactive.
|
|
const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
|
|
const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
|
|
|
|
// The number of events to be read at once for DisplayEventReceiver.
|
|
const int EVENT_BUFFER_SIZE = 100;
|
|
} // namespace
|
|
|
|
namespace android {
|
|
|
|
// --- PointerControllerContext ---
|
|
|
|
PointerControllerContext::PointerControllerContext(
|
|
const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
|
|
const sp<SpriteController>& spriteController, PointerController& controller)
|
|
: mPolicy(policy),
|
|
mLooper(looper),
|
|
mSpriteController(spriteController),
|
|
mHandler(new MessageHandler()),
|
|
mCallback(new LooperCallback()),
|
|
mController(controller),
|
|
mAnimator(*this) {
|
|
std::scoped_lock lock(mLock);
|
|
mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
|
|
}
|
|
|
|
PointerControllerContext::~PointerControllerContext() {
|
|
mLooper->removeMessages(mHandler);
|
|
}
|
|
|
|
void PointerControllerContext::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
|
|
std::scoped_lock lock(mLock);
|
|
|
|
if (mLocked.inactivityTimeout != inactivityTimeout) {
|
|
mLocked.inactivityTimeout = inactivityTimeout;
|
|
resetInactivityTimeoutLocked();
|
|
}
|
|
}
|
|
|
|
void PointerControllerContext::resetInactivityTimeout() {
|
|
std::scoped_lock lock(mLock);
|
|
resetInactivityTimeoutLocked();
|
|
}
|
|
|
|
void PointerControllerContext::resetInactivityTimeoutLocked() REQUIRES(mLock) {
|
|
mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
|
|
|
|
nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT
|
|
? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT
|
|
: INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
|
|
mLooper->sendMessageDelayed(timeout, mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
|
|
}
|
|
|
|
void PointerControllerContext::removeInactivityTimeout() {
|
|
std::scoped_lock lock(mLock);
|
|
mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
|
|
}
|
|
|
|
nsecs_t PointerControllerContext::getAnimationTime() REQUIRES(mAnimator.mLock) {
|
|
return mAnimator.getAnimationTimeLocked();
|
|
}
|
|
|
|
void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) {
|
|
mHandler->pointerController = controller;
|
|
}
|
|
|
|
void PointerControllerContext::setCallbackController(
|
|
std::shared_ptr<PointerController> controller) {
|
|
mCallback->pointerController = controller;
|
|
}
|
|
|
|
sp<PointerControllerPolicyInterface> PointerControllerContext::getPolicy() {
|
|
return mPolicy;
|
|
}
|
|
|
|
sp<SpriteController> PointerControllerContext::getSpriteController() {
|
|
return mSpriteController;
|
|
}
|
|
|
|
void PointerControllerContext::handleDisplayEvents() {
|
|
mAnimator.handleVsyncEvents();
|
|
}
|
|
|
|
void PointerControllerContext::MessageHandler::handleMessage(const Message& message) {
|
|
std::shared_ptr<PointerController> controller = pointerController.lock();
|
|
|
|
if (controller == nullptr) {
|
|
ALOGE("PointerController instance was released before processing message: what=%d",
|
|
message.what);
|
|
return;
|
|
}
|
|
switch (message.what) {
|
|
case MSG_INACTIVITY_TIMEOUT:
|
|
controller->doInactivityTimeout();
|
|
break;
|
|
}
|
|
}
|
|
|
|
int PointerControllerContext::LooperCallback::handleEvent(int /* fd */, int events,
|
|
void* /* data */) {
|
|
std::shared_ptr<PointerController> controller = pointerController.lock();
|
|
if (controller == nullptr) {
|
|
ALOGW("PointerController instance was released with pending callbacks. events=0x%x",
|
|
events);
|
|
return 0; // Remove the callback, the PointerController is gone anyways
|
|
}
|
|
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
|
|
ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", events);
|
|
return 0; // remove the callback
|
|
}
|
|
|
|
if (!(events & Looper::EVENT_INPUT)) {
|
|
ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events);
|
|
return 1; // keep the callback
|
|
}
|
|
|
|
controller->mContext.handleDisplayEvents();
|
|
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
|