blob: 4dfd05f476d57d9fad3f1cbb2ff5357ce69b64fa [file] [log] [blame]
Prabir Pradhanb56e92c2023-06-09 23:40:37 +00001/*
2 * Copyright 2023 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#define LOG_TAG "PointerChoreographer"
18
Byoungho Jungda10dd32023-10-06 17:03:45 +090019#include <android-base/logging.h>
20#include <input/PrintTools.h>
21
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000022#include "PointerChoreographer.h"
23
Byoungho Jungda10dd32023-10-06 17:03:45 +090024#define INDENT " "
25
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000026namespace android {
27
Byoungho Jungda10dd32023-10-06 17:03:45 +090028namespace {
29bool isFromMouse(const NotifyMotionArgs& args) {
30 return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
31 args.pointerProperties[0].toolType == ToolType::MOUSE;
32}
33
34} // namespace
35
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000036// --- PointerChoreographer ---
37
38PointerChoreographer::PointerChoreographer(InputListenerInterface& listener,
39 PointerChoreographerPolicyInterface& policy)
Byoungho Jungda10dd32023-10-06 17:03:45 +090040 : mNextListener(listener),
41 mPolicy(policy),
42 mDefaultMouseDisplayId(ADISPLAY_ID_DEFAULT),
43 mNotifiedPointerDisplayId(ADISPLAY_ID_NONE) {}
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000044
45void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +090046 std::scoped_lock _l(mLock);
47
48 mInputDeviceInfos = args.inputDeviceInfos;
49 updatePointerControllersLocked();
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000050 mNextListener.notify(args);
51}
52
53void PointerChoreographer::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) {
54 mNextListener.notify(args);
55}
56
57void PointerChoreographer::notifyKey(const NotifyKeyArgs& args) {
58 mNextListener.notify(args);
59}
60
61void PointerChoreographer::notifyMotion(const NotifyMotionArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +090062 NotifyMotionArgs newArgs = processMotion(args);
63
64 mNextListener.notify(newArgs);
65}
66
67NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& args) {
68 std::scoped_lock _l(mLock);
69
70 if (isFromMouse(args)) {
71 return processMouseEventLocked(args);
72 } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
73 return processTouchscreenEventLocked(args);
74 }
75 return args;
76}
77
78NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotionArgs& args) {
79 if (args.getPointerCount() != 1) {
80 LOG(FATAL) << "Wrong number of pointers " << args.dump();
81 }
82
83 const int32_t displayId = getTargetMouseDisplayLocked(args.displayId);
84 auto it = mMousePointersByDisplay.find(displayId);
85 if (it == mMousePointersByDisplay.end()) {
86 it = mMousePointersByDisplay
87 .insert({displayId,
88 mPolicy.createPointerController(
89 PointerControllerInterface::ControllerType::MOUSE)})
90 .first;
91 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
92 it->second->setDisplayViewport(*viewport);
93 }
94 notifyPointerDisplayIdChangedLocked();
95 }
96
97 PointerControllerInterface& pc = *it->second;
98
99 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
100 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
101 pc.move(deltaX, deltaY);
102 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
103
104 const auto [x, y] = pc.getPosition();
105 NotifyMotionArgs newArgs(args);
106 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
107 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
108 newArgs.xCursorPosition = x;
109 newArgs.yCursorPosition = y;
110 newArgs.displayId = displayId;
111 return newArgs;
112}
113
114/**
115 * When screen is touched, fade the mouse pointer on that display. We only call fade for
116 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
117 * mouse device keeps moving and unfades the cursor.
118 * For touch events, we do not need to populate the cursor position.
119 */
120NotifyMotionArgs PointerChoreographer::processTouchscreenEventLocked(const NotifyMotionArgs& args) {
121 if (const auto it = mMousePointersByDisplay.find(args.displayId);
122 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
123 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
124 }
125 return args;
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000126}
127
128void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
129 mNextListener.notify(args);
130}
131
132void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
133 mNextListener.notify(args);
134}
135
136void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
137 mNextListener.notify(args);
138}
139
140void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
141 mNextListener.notify(args);
142}
143
144void PointerChoreographer::notifyPointerCaptureChanged(
145 const NotifyPointerCaptureChangedArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900146 if (args.request.enable) {
147 std::scoped_lock _l(mLock);
148 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
149 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
150 }
151 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000152 mNextListener.notify(args);
153}
154
155void PointerChoreographer::dump(std::string& dump) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900156 std::scoped_lock _l(mLock);
157
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000158 dump += "PointerChoreographer:\n";
Byoungho Jungda10dd32023-10-06 17:03:45 +0900159
160 dump += INDENT "MousePointerControllers:\n";
161 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
162 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
163 dump += INDENT + std::to_string(displayId) + " : " + pointerControllerDump;
164 }
165 dump += "\n";
166}
167
168const DisplayViewport* PointerChoreographer::findViewportByIdLocked(int32_t displayId) const {
169 for (auto& viewport : mViewports) {
170 if (viewport.displayId == displayId) {
171 return &viewport;
172 }
173 }
174 return nullptr;
175}
176
177int32_t PointerChoreographer::getTargetMouseDisplayLocked(int32_t associatedDisplayId) const {
178 return associatedDisplayId == ADISPLAY_ID_NONE ? mDefaultMouseDisplayId : associatedDisplayId;
179}
180
181void PointerChoreographer::updatePointerControllersLocked() {
182 std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
183
184 // Mark the displayIds or deviceIds of PointerControllers currently needed.
185 for (const auto& info : mInputDeviceInfos) {
186 const uint32_t sources = info.getSources();
187 if (isFromSource(sources, AINPUT_SOURCE_MOUSE) ||
188 isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE)) {
189 const int32_t resolvedDisplayId =
190 getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
191 mouseDisplaysToKeep.insert(resolvedDisplayId);
192 }
193 }
194
195 // Remove PointerControllers no longer needed.
196 // This has the side-effect of fading pointers or clearing spots before removal.
197 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& item) {
198 if (mouseDisplaysToKeep.find(item.first) == mouseDisplaysToKeep.end()) {
199 item.second->fade(PointerControllerInterface::Transition::IMMEDIATE);
200 return true;
201 }
202 return false;
203 });
204
205 // Notify the policy if there's a change on the pointer display ID.
206 notifyPointerDisplayIdChangedLocked();
207}
208
209void PointerChoreographer::notifyPointerDisplayIdChangedLocked() {
210 int32_t displayIdToNotify = ADISPLAY_ID_NONE;
211 FloatPoint cursorPosition = {0, 0};
212 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
213 it != mMousePointersByDisplay.end()) {
214 displayIdToNotify = it->second->getDisplayId();
215 cursorPosition = it->second->getPosition();
216 }
217
218 if (mNotifiedPointerDisplayId == displayIdToNotify) {
219 return;
220 }
221 mPolicy.notifyPointerDisplayIdChanged(displayIdToNotify, cursorPosition);
222 mNotifiedPointerDisplayId = displayIdToNotify;
223}
224
225void PointerChoreographer::setDefaultMouseDisplayId(int32_t displayId) {
226 std::scoped_lock _l(mLock);
227
228 mDefaultMouseDisplayId = displayId;
229 updatePointerControllersLocked();
230}
231
232void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
233 std::scoped_lock _l(mLock);
234 for (const auto& viewport : viewports) {
235 int32_t displayId = viewport.displayId;
236 if (const auto it = mMousePointersByDisplay.find(displayId);
237 it != mMousePointersByDisplay.end()) {
238 it->second->setDisplayViewport(viewport);
239 }
240 }
241 mViewports = viewports;
242 notifyPointerDisplayIdChangedLocked();
243}
244
245std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
246 int32_t associatedDisplayId) {
247 std::scoped_lock _l(mLock);
248 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
249 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
250 return *viewport;
251 }
252 return std::nullopt;
253}
254
255FloatPoint PointerChoreographer::getMouseCursorPosition(int32_t displayId) {
256 std::scoped_lock _l(mLock);
257 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
258 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
259 it != mMousePointersByDisplay.end()) {
260 return it->second->getPosition();
261 }
262 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000263}
264
265} // namespace android