/* * 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& policy, const sp& looper, const sp& 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 controller) { mHandler->pointerController = controller; } void PointerControllerContext::setCallbackController( std::shared_ptr controller) { mCallback->pointerController = controller; } sp PointerControllerContext::getPolicy() { return mPolicy; } sp PointerControllerContext::getSpriteController() { return mSpriteController; } void PointerControllerContext::handleDisplayEvents() { mAnimator.handleVsyncEvents(); } void PointerControllerContext::MessageHandler::handleMessage(const Message& message) { std::shared_ptr 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 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 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 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(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