blob: 5406de8602d61f31626b3fefa8ba68fafcca8d33 [file] [log] [blame]
Liam Harringtonc782be62020-07-17 19:48:24 +00001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "PointerControllerContext.h"
Manasi Navare1e4d6e02025-02-04 01:01:01 +000018
Liam Harringtonc782be62020-07-17 19:48:24 +000019#include "PointerController.h"
20
21namespace {
22// Time to wait before starting the fade when the pointer is inactive.
23const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
24const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
25
26// The number of events to be read at once for DisplayEventReceiver.
27const int EVENT_BUFFER_SIZE = 100;
28} // namespace
29
30namespace android {
31
32// --- PointerControllerContext ---
33
34PointerControllerContext::PointerControllerContext(
35 const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
Prabir Pradhan27c6d992023-08-18 19:44:55 +000036 SpriteController& spriteController, PointerController& controller)
Liam Harringtonc782be62020-07-17 19:48:24 +000037 : mPolicy(policy),
38 mLooper(looper),
39 mSpriteController(spriteController),
Prabir Pradhan4cc1a632023-06-09 21:31:26 +000040 mHandler(sp<MessageHandler>::make()),
41 mCallback(sp<LooperCallback>::make()),
Liam Harringtonce637132020-08-14 04:00:11 +000042 mController(controller),
43 mAnimator(*this) {
Liam Harringtonc782be62020-07-17 19:48:24 +000044 std::scoped_lock lock(mLock);
45 mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
Liam Harringtonc782be62020-07-17 19:48:24 +000046}
47
48PointerControllerContext::~PointerControllerContext() {
49 mLooper->removeMessages(mHandler);
50}
51
52void PointerControllerContext::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
53 std::scoped_lock lock(mLock);
54
55 if (mLocked.inactivityTimeout != inactivityTimeout) {
56 mLocked.inactivityTimeout = inactivityTimeout;
57 resetInactivityTimeoutLocked();
58 }
59}
60
Liam Harringtonc782be62020-07-17 19:48:24 +000061void PointerControllerContext::resetInactivityTimeout() {
62 std::scoped_lock lock(mLock);
63 resetInactivityTimeoutLocked();
64}
65
66void PointerControllerContext::resetInactivityTimeoutLocked() REQUIRES(mLock) {
67 mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
68
69 nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT
70 ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT
71 : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
72 mLooper->sendMessageDelayed(timeout, mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
73}
74
75void PointerControllerContext::removeInactivityTimeout() {
76 std::scoped_lock lock(mLock);
77 mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
78}
79
Liam Harringtonce637132020-08-14 04:00:11 +000080nsecs_t PointerControllerContext::getAnimationTime() REQUIRES(mAnimator.mLock) {
81 return mAnimator.getAnimationTimeLocked();
Liam Harringtonc782be62020-07-17 19:48:24 +000082}
83
84void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) {
85 mHandler->pointerController = controller;
86}
87
88void PointerControllerContext::setCallbackController(
89 std::shared_ptr<PointerController> controller) {
90 mCallback->pointerController = controller;
91}
92
93sp<PointerControllerPolicyInterface> PointerControllerContext::getPolicy() {
94 return mPolicy;
95}
96
Prabir Pradhan27c6d992023-08-18 19:44:55 +000097SpriteController& PointerControllerContext::getSpriteController() {
Liam Harringtonc782be62020-07-17 19:48:24 +000098 return mSpriteController;
99}
100
Liam Harringtonc782be62020-07-17 19:48:24 +0000101void PointerControllerContext::handleDisplayEvents() {
Liam Harringtonce637132020-08-14 04:00:11 +0000102 mAnimator.handleVsyncEvents();
Liam Harringtonc782be62020-07-17 19:48:24 +0000103}
104
105void PointerControllerContext::MessageHandler::handleMessage(const Message& message) {
106 std::shared_ptr<PointerController> controller = pointerController.lock();
107
108 if (controller == nullptr) {
109 ALOGE("PointerController instance was released before processing message: what=%d",
110 message.what);
111 return;
112 }
113 switch (message.what) {
114 case MSG_INACTIVITY_TIMEOUT:
115 controller->doInactivityTimeout();
116 break;
117 }
118}
119
120int PointerControllerContext::LooperCallback::handleEvent(int /* fd */, int events,
121 void* /* data */) {
122 std::shared_ptr<PointerController> controller = pointerController.lock();
123 if (controller == nullptr) {
124 ALOGW("PointerController instance was released with pending callbacks. events=0x%x",
125 events);
126 return 0; // Remove the callback, the PointerController is gone anyways
127 }
128 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
129 ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", events);
130 return 0; // remove the callback
131 }
132
133 if (!(events & Looper::EVENT_INPUT)) {
134 ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events);
135 return 1; // keep the callback
136 }
137
138 controller->mContext.handleDisplayEvents();
139 return 1; // keep the callback
140}
141
Linnan Li0defadf2024-05-05 19:17:05 +0800142void PointerControllerContext::addAnimationCallback(ui::LogicalDisplayId displayId,
Liam Harringtonce637132020-08-14 04:00:11 +0000143 std::function<bool(nsecs_t)> callback) {
144 mAnimator.addCallback(displayId, callback);
145}
146
Linnan Li0defadf2024-05-05 19:17:05 +0800147void PointerControllerContext::removeAnimationCallback(ui::LogicalDisplayId displayId) {
Liam Harringtonce637132020-08-14 04:00:11 +0000148 mAnimator.removeCallback(displayId);
149}
150
151PointerControllerContext::PointerAnimator::PointerAnimator(PointerControllerContext& context)
152 : mContext(context) {
153 initializeDisplayEventReceiver();
154}
155
156void PointerControllerContext::PointerAnimator::initializeDisplayEventReceiver() {
157 if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
158 mContext.mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
159 Looper::EVENT_INPUT, mContext.mCallback, nullptr);
160 } else {
161 ALOGE("Failed to initialize DisplayEventReceiver.");
162 }
163}
164
Linnan Li0defadf2024-05-05 19:17:05 +0800165void PointerControllerContext::PointerAnimator::addCallback(ui::LogicalDisplayId displayId,
Liam Harringtonce637132020-08-14 04:00:11 +0000166 std::function<bool(nsecs_t)> callback) {
167 std::scoped_lock lock(mLock);
168 mLocked.callbacks[displayId] = callback;
169 startAnimationLocked();
170}
171
Linnan Li0defadf2024-05-05 19:17:05 +0800172void PointerControllerContext::PointerAnimator::removeCallback(ui::LogicalDisplayId displayId) {
Liam Harringtonce637132020-08-14 04:00:11 +0000173 std::scoped_lock lock(mLock);
174 auto it = mLocked.callbacks.find(displayId);
175 if (it == mLocked.callbacks.end()) {
176 return;
177 }
178 mLocked.callbacks.erase(it);
179}
180
181void PointerControllerContext::PointerAnimator::handleVsyncEvents() {
182 bool gotVsync = false;
183 ssize_t n;
184 nsecs_t timestamp;
185 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
186 while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
187 for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
Manasi Navare1e4d6e02025-02-04 01:01:01 +0000188 if (buf[i].header.type == DisplayEventType::DISPLAY_EVENT_VSYNC) {
Liam Harringtonce637132020-08-14 04:00:11 +0000189 timestamp = buf[i].header.timestamp;
190 gotVsync = true;
191 }
192 }
193 }
194 if (gotVsync) {
195 std::scoped_lock lock(mLock);
196 mLocked.animationPending = false;
197 handleCallbacksLocked(timestamp);
198 }
199}
200
201nsecs_t PointerControllerContext::PointerAnimator::getAnimationTimeLocked() REQUIRES(mLock) {
202 return mLocked.animationTime;
203}
204
205void PointerControllerContext::PointerAnimator::startAnimationLocked() REQUIRES(mLock) {
206 if (!mLocked.animationPending) {
207 mLocked.animationPending = true;
208 mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
209 mDisplayEventReceiver.requestNextVsync();
210 }
211}
212
213void PointerControllerContext::PointerAnimator::handleCallbacksLocked(nsecs_t timestamp)
214 REQUIRES(mLock) {
215 for (auto it = mLocked.callbacks.begin(); it != mLocked.callbacks.end();) {
216 bool keepCallback = it->second(timestamp);
217 if (!keepCallback) {
218 it = mLocked.callbacks.erase(it);
219 } else {
220 ++it;
221 }
222 }
223
224 if (!mLocked.callbacks.empty()) {
225 startAnimationLocked();
226 }
227}
228
Liam Harringtonc782be62020-07-17 19:48:24 +0000229} // namespace android