blob: 1092bdb90e65cbad9ff783df91fb9656eb452111 [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) {
Prabir Pradhan19767602023-11-03 16:53:31 +000080 LOG(FATAL) << "Only mouse events with a single pointer are currently supported: "
81 << args.dump();
Byoungho Jungda10dd32023-10-06 17:03:45 +090082 }
83
84 const int32_t displayId = getTargetMouseDisplayLocked(args.displayId);
Prabir Pradhan19767602023-11-03 16:53:31 +000085
86 // Get the mouse pointer controller for the display, or create one if it doesn't exist.
87 auto [it, emplaced] =
88 mMousePointersByDisplay.try_emplace(displayId,
89 getMouseControllerConstructor(displayId));
90 if (emplaced) {
Byoungho Jungda10dd32023-10-06 17:03:45 +090091 notifyPointerDisplayIdChangedLocked();
92 }
93
94 PointerControllerInterface& pc = *it->second;
95
96 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
97 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
98 pc.move(deltaX, deltaY);
99 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
100
101 const auto [x, y] = pc.getPosition();
102 NotifyMotionArgs newArgs(args);
103 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
104 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
105 newArgs.xCursorPosition = x;
106 newArgs.yCursorPosition = y;
107 newArgs.displayId = displayId;
108 return newArgs;
109}
110
111/**
112 * When screen is touched, fade the mouse pointer on that display. We only call fade for
113 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
114 * mouse device keeps moving and unfades the cursor.
115 * For touch events, we do not need to populate the cursor position.
116 */
117NotifyMotionArgs PointerChoreographer::processTouchscreenEventLocked(const NotifyMotionArgs& args) {
118 if (const auto it = mMousePointersByDisplay.find(args.displayId);
119 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
120 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
121 }
122 return args;
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000123}
124
125void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
126 mNextListener.notify(args);
127}
128
129void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
130 mNextListener.notify(args);
131}
132
133void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
134 mNextListener.notify(args);
135}
136
137void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
138 mNextListener.notify(args);
139}
140
141void PointerChoreographer::notifyPointerCaptureChanged(
142 const NotifyPointerCaptureChangedArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900143 if (args.request.enable) {
144 std::scoped_lock _l(mLock);
145 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
146 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
147 }
148 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000149 mNextListener.notify(args);
150}
151
152void PointerChoreographer::dump(std::string& dump) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900153 std::scoped_lock _l(mLock);
154
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000155 dump += "PointerChoreographer:\n";
Byoungho Jungda10dd32023-10-06 17:03:45 +0900156
157 dump += INDENT "MousePointerControllers:\n";
158 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
159 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
160 dump += INDENT + std::to_string(displayId) + " : " + pointerControllerDump;
161 }
162 dump += "\n";
163}
164
165const DisplayViewport* PointerChoreographer::findViewportByIdLocked(int32_t displayId) const {
166 for (auto& viewport : mViewports) {
167 if (viewport.displayId == displayId) {
168 return &viewport;
169 }
170 }
171 return nullptr;
172}
173
174int32_t PointerChoreographer::getTargetMouseDisplayLocked(int32_t associatedDisplayId) const {
175 return associatedDisplayId == ADISPLAY_ID_NONE ? mDefaultMouseDisplayId : associatedDisplayId;
176}
177
178void PointerChoreographer::updatePointerControllersLocked() {
179 std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
180
181 // Mark the displayIds or deviceIds of PointerControllers currently needed.
182 for (const auto& info : mInputDeviceInfos) {
183 const uint32_t sources = info.getSources();
184 if (isFromSource(sources, AINPUT_SOURCE_MOUSE) ||
185 isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE)) {
186 const int32_t resolvedDisplayId =
187 getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
188 mouseDisplaysToKeep.insert(resolvedDisplayId);
189 }
190 }
191
192 // Remove PointerControllers no longer needed.
193 // This has the side-effect of fading pointers or clearing spots before removal.
Prabir Pradhan19767602023-11-03 16:53:31 +0000194 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
195 auto& [displayId, controller] = pair;
196 if (mouseDisplaysToKeep.find(displayId) == mouseDisplaysToKeep.end()) {
197 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900198 return true;
199 }
200 return false;
201 });
202
203 // Notify the policy if there's a change on the pointer display ID.
204 notifyPointerDisplayIdChangedLocked();
205}
206
207void PointerChoreographer::notifyPointerDisplayIdChangedLocked() {
208 int32_t displayIdToNotify = ADISPLAY_ID_NONE;
209 FloatPoint cursorPosition = {0, 0};
210 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
211 it != mMousePointersByDisplay.end()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000212 const auto& pointerController = it->second;
213 // Use the displayId from the pointerController, because it accurately reflects whether
214 // the viewport has been added for that display. Otherwise, we would have to check if
215 // the viewport exists separately.
216 displayIdToNotify = pointerController->getDisplayId();
217 cursorPosition = pointerController->getPosition();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900218 }
219
220 if (mNotifiedPointerDisplayId == displayIdToNotify) {
221 return;
222 }
223 mPolicy.notifyPointerDisplayIdChanged(displayIdToNotify, cursorPosition);
224 mNotifiedPointerDisplayId = displayIdToNotify;
225}
226
227void PointerChoreographer::setDefaultMouseDisplayId(int32_t displayId) {
228 std::scoped_lock _l(mLock);
229
230 mDefaultMouseDisplayId = displayId;
231 updatePointerControllersLocked();
232}
233
234void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
235 std::scoped_lock _l(mLock);
236 for (const auto& viewport : viewports) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000237 if (const auto it = mMousePointersByDisplay.find(viewport.displayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900238 it != mMousePointersByDisplay.end()) {
239 it->second->setDisplayViewport(viewport);
240 }
241 }
242 mViewports = viewports;
243 notifyPointerDisplayIdChangedLocked();
244}
245
246std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
247 int32_t associatedDisplayId) {
248 std::scoped_lock _l(mLock);
249 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
250 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
251 return *viewport;
252 }
253 return std::nullopt;
254}
255
256FloatPoint PointerChoreographer::getMouseCursorPosition(int32_t displayId) {
257 std::scoped_lock _l(mLock);
258 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
259 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
260 it != mMousePointersByDisplay.end()) {
261 return it->second->getPosition();
262 }
263 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000264}
265
Prabir Pradhan19767602023-11-03 16:53:31 +0000266PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
267 int32_t displayId) {
268 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
269 [this, displayId]() REQUIRES(mLock) {
270 auto pc = mPolicy.createPointerController(
271 PointerControllerInterface::ControllerType::MOUSE);
272 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
273 pc->setDisplayViewport(*viewport);
274 }
275 return pc;
276 };
277 return ConstructorDelegate(std::move(ctor));
278}
279
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000280} // namespace android