1 /*
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"
18
19 #include "PointerController.h"
20
21 namespace {
22 // Time to wait before starting the fade when the pointer is inactive.
23 const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
24 const 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.
27 const int EVENT_BUFFER_SIZE = 100;
28 } // namespace
29
30 namespace android {
31
32 // --- PointerControllerContext ---
33
PointerControllerContext(const sp<PointerControllerPolicyInterface> & policy,const sp<Looper> & looper,SpriteController & spriteController,PointerController & controller)34 PointerControllerContext::PointerControllerContext(
35 const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
36 SpriteController& spriteController, PointerController& controller)
37 : mPolicy(policy),
38 mLooper(looper),
39 mSpriteController(spriteController),
40 mHandler(sp<MessageHandler>::make()),
41 mCallback(sp<LooperCallback>::make()),
42 mController(controller),
43 mAnimator(*this) {
44 std::scoped_lock lock(mLock);
45 mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
46 }
47
~PointerControllerContext()48 PointerControllerContext::~PointerControllerContext() {
49 mLooper->removeMessages(mHandler);
50 }
51
setInactivityTimeout(InactivityTimeout inactivityTimeout)52 void 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
resetInactivityTimeout()61 void PointerControllerContext::resetInactivityTimeout() {
62 std::scoped_lock lock(mLock);
63 resetInactivityTimeoutLocked();
64 }
65
resetInactivityTimeoutLocked()66 void 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
removeInactivityTimeout()75 void PointerControllerContext::removeInactivityTimeout() {
76 std::scoped_lock lock(mLock);
77 mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT);
78 }
79
getAnimationTime()80 nsecs_t PointerControllerContext::getAnimationTime() REQUIRES(mAnimator.mLock) {
81 return mAnimator.getAnimationTimeLocked();
82 }
83
setHandlerController(std::shared_ptr<PointerController> controller)84 void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) {
85 mHandler->pointerController = controller;
86 }
87
setCallbackController(std::shared_ptr<PointerController> controller)88 void PointerControllerContext::setCallbackController(
89 std::shared_ptr<PointerController> controller) {
90 mCallback->pointerController = controller;
91 }
92
getPolicy()93 sp<PointerControllerPolicyInterface> PointerControllerContext::getPolicy() {
94 return mPolicy;
95 }
96
getSpriteController()97 SpriteController& PointerControllerContext::getSpriteController() {
98 return mSpriteController;
99 }
100
handleDisplayEvents()101 void PointerControllerContext::handleDisplayEvents() {
102 mAnimator.handleVsyncEvents();
103 }
104
handleMessage(const Message & message)105 void 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
handleEvent(int,int events,void *)120 int 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
addAnimationCallback(ui::LogicalDisplayId displayId,std::function<bool (nsecs_t)> callback)142 void PointerControllerContext::addAnimationCallback(ui::LogicalDisplayId displayId,
143 std::function<bool(nsecs_t)> callback) {
144 mAnimator.addCallback(displayId, callback);
145 }
146
removeAnimationCallback(ui::LogicalDisplayId displayId)147 void PointerControllerContext::removeAnimationCallback(ui::LogicalDisplayId displayId) {
148 mAnimator.removeCallback(displayId);
149 }
150
PointerAnimator(PointerControllerContext & context)151 PointerControllerContext::PointerAnimator::PointerAnimator(PointerControllerContext& context)
152 : mContext(context) {
153 initializeDisplayEventReceiver();
154 }
155
initializeDisplayEventReceiver()156 void 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
addCallback(ui::LogicalDisplayId displayId,std::function<bool (nsecs_t)> callback)165 void PointerControllerContext::PointerAnimator::addCallback(ui::LogicalDisplayId displayId,
166 std::function<bool(nsecs_t)> callback) {
167 std::scoped_lock lock(mLock);
168 mLocked.callbacks[displayId] = callback;
169 startAnimationLocked();
170 }
171
removeCallback(ui::LogicalDisplayId displayId)172 void PointerControllerContext::PointerAnimator::removeCallback(ui::LogicalDisplayId displayId) {
173 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
handleVsyncEvents()181 void 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) {
188 if (buf[i].header.type == DisplayEventType::DISPLAY_EVENT_VSYNC) {
189 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
getAnimationTimeLocked()201 nsecs_t PointerControllerContext::PointerAnimator::getAnimationTimeLocked() REQUIRES(mLock) {
202 return mLocked.animationTime;
203 }
204
startAnimationLocked()205 void 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
handleCallbacksLocked(nsecs_t timestamp)213 void 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
229 } // namespace android
230