blob: c333814078bc124a509ead33b9cc6b065d0b70ad [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 {
Prabir Pradhan5a51a222024-03-05 03:54:00 +000029
Byoungho Jungda10dd32023-10-06 17:03:45 +090030bool isFromMouse(const NotifyMotionArgs& args) {
31 return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
32 args.pointerProperties[0].toolType == ToolType::MOUSE;
33}
34
Byoungho Jungee6268f2023-10-30 17:27:26 +090035bool isFromTouchpad(const NotifyMotionArgs& args) {
36 return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
37 args.pointerProperties[0].toolType == ToolType::FINGER;
38}
39
Byoungho Jungd6fe27b2023-10-27 20:49:38 +090040bool isHoverAction(int32_t action) {
41 return action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
42 action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT;
43}
44
45bool isStylusHoverEvent(const NotifyMotionArgs& args) {
46 return isStylusEvent(args.source, args.pointerProperties) && isHoverAction(args.action);
47}
Prabir Pradhan5a51a222024-03-05 03:54:00 +000048
49inline void notifyPointerDisplayChange(std::optional<std::tuple<int32_t, FloatPoint>> change,
50 PointerChoreographerPolicyInterface& policy) {
51 if (!change) {
52 return;
53 }
54 const auto& [displayId, cursorPosition] = *change;
55 policy.notifyPointerDisplayIdChanged(displayId, cursorPosition);
56}
57
Byoungho Jungda10dd32023-10-06 17:03:45 +090058} // namespace
59
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000060// --- PointerChoreographer ---
61
62PointerChoreographer::PointerChoreographer(InputListenerInterface& listener,
63 PointerChoreographerPolicyInterface& policy)
Prabir Pradhan5a51a222024-03-05 03:54:00 +000064 : mTouchControllerConstructor([this]() {
Prabir Pradhan16788792023-11-08 21:07:21 +000065 return mPolicy.createPointerController(
66 PointerControllerInterface::ControllerType::TOUCH);
67 }),
68 mNextListener(listener),
Byoungho Jungda10dd32023-10-06 17:03:45 +090069 mPolicy(policy),
70 mDefaultMouseDisplayId(ADISPLAY_ID_DEFAULT),
Byoungho Jung6f5b16b2023-10-27 18:22:07 +090071 mNotifiedPointerDisplayId(ADISPLAY_ID_NONE),
Byoungho Jungd6fe27b2023-10-27 20:49:38 +090072 mShowTouchesEnabled(false),
73 mStylusPointerIconEnabled(false) {}
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000074
75void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +000076 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +090077
Prabir Pradhan5a51a222024-03-05 03:54:00 +000078 { // acquire lock
79 std::scoped_lock _l(mLock);
80
81 mInputDeviceInfos = args.inputDeviceInfos;
82 pointerDisplayChange = updatePointerControllersLocked();
83 } // release lock
84
85 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000086 mNextListener.notify(args);
87}
88
89void PointerChoreographer::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) {
90 mNextListener.notify(args);
91}
92
93void PointerChoreographer::notifyKey(const NotifyKeyArgs& args) {
94 mNextListener.notify(args);
95}
96
97void PointerChoreographer::notifyMotion(const NotifyMotionArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +090098 NotifyMotionArgs newArgs = processMotion(args);
99
100 mNextListener.notify(newArgs);
101}
102
103NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& args) {
104 std::scoped_lock _l(mLock);
105
106 if (isFromMouse(args)) {
107 return processMouseEventLocked(args);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900108 } else if (isFromTouchpad(args)) {
109 return processTouchpadEventLocked(args);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900110 } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
111 processStylusHoverEventLocked(args);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900112 } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900113 processTouchscreenAndStylusEventLocked(args);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900114 }
115 return args;
116}
117
118NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotionArgs& args) {
119 if (args.getPointerCount() != 1) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000120 LOG(FATAL) << "Only mouse events with a single pointer are currently supported: "
121 << args.dump();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900122 }
123
Prabir Pradhan990d8712024-03-05 00:31:36 +0000124 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900125 NotifyMotionArgs newArgs(args);
126 newArgs.displayId = displayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900127
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900128 if (MotionEvent::isValidCursorPosition(args.xCursorPosition, args.yCursorPosition)) {
129 // This is an absolute mouse device that knows about the location of the cursor on the
130 // display, so set the cursor position to the specified location.
131 const auto [x, y] = pc.getPosition();
132 const float deltaX = args.xCursorPosition - x;
133 const float deltaY = args.yCursorPosition - y;
134 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
135 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
136 pc.setPosition(args.xCursorPosition, args.yCursorPosition);
137 } else {
138 // This is a relative mouse, so move the cursor by the specified amount.
139 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
140 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
141 pc.move(deltaX, deltaY);
142 const auto [x, y] = pc.getPosition();
143 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
144 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
145 newArgs.xCursorPosition = x;
146 newArgs.yCursorPosition = y;
147 }
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000148 if (canUnfadeOnDisplay(displayId)) {
149 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
150 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900151 return newArgs;
152}
153
Byoungho Jungee6268f2023-10-30 17:27:26 +0900154NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
Prabir Pradhan990d8712024-03-05 00:31:36 +0000155 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900156
157 NotifyMotionArgs newArgs(args);
158 newArgs.displayId = displayId;
159 if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
160 // This is a movement of the mouse pointer.
161 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
162 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
163 pc.move(deltaX, deltaY);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000164 if (canUnfadeOnDisplay(displayId)) {
165 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
166 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900167
168 const auto [x, y] = pc.getPosition();
169 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
170 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
171 newArgs.xCursorPosition = x;
172 newArgs.yCursorPosition = y;
173 } else {
174 // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000175 if (canUnfadeOnDisplay(displayId)) {
176 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
177 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900178
179 const auto [x, y] = pc.getPosition();
180 for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
181 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
182 args.pointerCoords[i].getX() + x);
183 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
184 args.pointerCoords[i].getY() + y);
185 }
186 newArgs.xCursorPosition = x;
187 newArgs.yCursorPosition = y;
188 }
189 return newArgs;
190}
191
Byoungho Jungda10dd32023-10-06 17:03:45 +0900192/**
193 * When screen is touched, fade the mouse pointer on that display. We only call fade for
194 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
195 * mouse device keeps moving and unfades the cursor.
196 * For touch events, we do not need to populate the cursor position.
197 */
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900198void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) {
199 if (args.displayId == ADISPLAY_ID_NONE) {
200 return;
201 }
202
Byoungho Jungda10dd32023-10-06 17:03:45 +0900203 if (const auto it = mMousePointersByDisplay.find(args.displayId);
204 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
205 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
206 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900207
208 if (!mShowTouchesEnabled) {
209 return;
210 }
211
212 // Get the touch pointer controller for the device, or create one if it doesn't exist.
Prabir Pradhan16788792023-11-08 21:07:21 +0000213 auto [it, _] = mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900214
215 PointerControllerInterface& pc = *it->second;
216
217 const PointerCoords* coords = args.pointerCoords.data();
218 const int32_t maskedAction = MotionEvent::getActionMasked(args.action);
219 const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
220 std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
221 BitSet32 idBits;
222 if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL) {
223 for (size_t i = 0; i < args.getPointerCount(); i++) {
224 if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
225 continue;
226 }
227 uint32_t id = args.pointerProperties[i].id;
228 idToIndex[id] = i;
229 idBits.markBit(id);
230 }
231 }
232 // The PointerController already handles setting spots per-display, so
233 // we do not need to manually manage display changes for touch spots for now.
234 pc.setSpots(coords, idToIndex.cbegin(), idBits, args.displayId);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000235}
236
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900237void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& args) {
238 if (args.displayId == ADISPLAY_ID_NONE) {
239 return;
240 }
241
242 if (args.getPointerCount() != 1) {
243 LOG(WARNING) << "Only stylus hover events with a single pointer are currently supported: "
244 << args.dump();
245 }
246
247 // Get the stylus pointer controller for the device, or create one if it doesn't exist.
248 auto [it, _] =
249 mStylusPointersByDevice.try_emplace(args.deviceId,
250 getStylusControllerConstructor(args.displayId));
251
252 PointerControllerInterface& pc = *it->second;
253
254 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
255 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
256 pc.setPosition(x, y);
257 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
258 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhan4b36db92024-01-03 20:56:57 +0000259 pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000260 } else if (canUnfadeOnDisplay(args.displayId)) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900261 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
262 }
263}
264
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000265void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
266 mNextListener.notify(args);
267}
268
269void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
270 mNextListener.notify(args);
271}
272
273void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
274 mNextListener.notify(args);
275}
276
277void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900278 processDeviceReset(args);
279
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000280 mNextListener.notify(args);
281}
282
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900283void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) {
284 std::scoped_lock _l(mLock);
Prabir Pradhan16788792023-11-08 21:07:21 +0000285 mTouchPointersByDevice.erase(args.deviceId);
286 mStylusPointersByDevice.erase(args.deviceId);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900287}
288
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000289void PointerChoreographer::notifyPointerCaptureChanged(
290 const NotifyPointerCaptureChangedArgs& args) {
Hiroki Sato25040232024-02-22 17:21:22 +0900291 if (args.request.isEnable()) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900292 std::scoped_lock _l(mLock);
293 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
294 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
295 }
296 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000297 mNextListener.notify(args);
298}
299
300void PointerChoreographer::dump(std::string& dump) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900301 std::scoped_lock _l(mLock);
302
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000303 dump += "PointerChoreographer:\n";
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900304 dump += StringPrintf("show touches: %s\n", mShowTouchesEnabled ? "true" : "false");
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900305 dump += StringPrintf("stylus pointer icon enabled: %s\n",
306 mStylusPointerIconEnabled ? "true" : "false");
Byoungho Jungda10dd32023-10-06 17:03:45 +0900307
308 dump += INDENT "MousePointerControllers:\n";
309 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
310 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
311 dump += INDENT + std::to_string(displayId) + " : " + pointerControllerDump;
312 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900313 dump += INDENT "TouchPointerControllers:\n";
314 for (const auto& [deviceId, touchPointerController] : mTouchPointersByDevice) {
315 std::string pointerControllerDump = addLinePrefix(touchPointerController->dump(), INDENT);
316 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
317 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900318 dump += INDENT "StylusPointerControllers:\n";
319 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
320 std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
321 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
322 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900323 dump += "\n";
324}
325
326const DisplayViewport* PointerChoreographer::findViewportByIdLocked(int32_t displayId) const {
327 for (auto& viewport : mViewports) {
328 if (viewport.displayId == displayId) {
329 return &viewport;
330 }
331 }
332 return nullptr;
333}
334
335int32_t PointerChoreographer::getTargetMouseDisplayLocked(int32_t associatedDisplayId) const {
336 return associatedDisplayId == ADISPLAY_ID_NONE ? mDefaultMouseDisplayId : associatedDisplayId;
337}
338
Prabir Pradhan990d8712024-03-05 00:31:36 +0000339std::pair<int32_t, PointerControllerInterface&> PointerChoreographer::ensureMouseControllerLocked(
340 int32_t associatedDisplayId) {
Byoungho Jungee6268f2023-10-30 17:27:26 +0900341 const int32_t displayId = getTargetMouseDisplayLocked(associatedDisplayId);
342
Prabir Pradhan990d8712024-03-05 00:31:36 +0000343 auto it = mMousePointersByDisplay.find(displayId);
344 LOG_ALWAYS_FATAL_IF(it == mMousePointersByDisplay.end(),
345 "There is no mouse controller created for display %d", displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900346
347 return {displayId, *it->second};
348}
349
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900350InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000351 auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
352 [deviceId](const auto& info) { return info.getId() == deviceId; });
353 return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900354}
355
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000356bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) {
357 return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
358}
359
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000360PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900361 std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900362 std::set<DeviceId> touchDevicesToKeep;
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900363 std::set<DeviceId> stylusDevicesToKeep;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900364
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000365 // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
366 // new PointerControllers if necessary.
Byoungho Jungda10dd32023-10-06 17:03:45 +0900367 for (const auto& info : mInputDeviceInfos) {
368 const uint32_t sources = info.getSources();
369 if (isFromSource(sources, AINPUT_SOURCE_MOUSE) ||
370 isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000371 const int32_t displayId = getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
372 mouseDisplaysToKeep.insert(displayId);
373 // For mice, show the cursor immediately when the device is first connected or
374 // when it moves to a new display.
375 auto [mousePointerIt, isNewMousePointer] =
376 mMousePointersByDisplay.try_emplace(displayId,
377 getMouseControllerConstructor(displayId));
378 auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId());
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000379 if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000380 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
381 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900382 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900383 if (isFromSource(sources, AINPUT_SOURCE_TOUCHSCREEN) && mShowTouchesEnabled &&
384 info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) {
385 touchDevicesToKeep.insert(info.getId());
386 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900387 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && mStylusPointerIconEnabled &&
388 info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) {
389 stylusDevicesToKeep.insert(info.getId());
390 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900391 }
392
393 // Remove PointerControllers no longer needed.
Prabir Pradhan19767602023-11-03 16:53:31 +0000394 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000395 return mouseDisplaysToKeep.find(pair.first) == mouseDisplaysToKeep.end();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900396 });
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900397 std::erase_if(mTouchPointersByDevice, [&touchDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000398 return touchDevicesToKeep.find(pair.first) == touchDevicesToKeep.end();
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900399 });
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900400 std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000401 return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900402 });
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000403 std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(mLock) {
404 return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
405 [id](const auto& info) { return info.getId() == id; }) ==
406 mInputDeviceInfos.end();
407 });
Byoungho Jungda10dd32023-10-06 17:03:45 +0900408
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000409 // Check if we need to notify the policy if there's a change on the pointer display ID.
410 return calculatePointerDisplayChangeToNotify();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900411}
412
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000413PointerChoreographer::PointerDisplayChange
414PointerChoreographer::calculatePointerDisplayChangeToNotify() {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900415 int32_t displayIdToNotify = ADISPLAY_ID_NONE;
416 FloatPoint cursorPosition = {0, 0};
417 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
418 it != mMousePointersByDisplay.end()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000419 const auto& pointerController = it->second;
420 // Use the displayId from the pointerController, because it accurately reflects whether
421 // the viewport has been added for that display. Otherwise, we would have to check if
422 // the viewport exists separately.
423 displayIdToNotify = pointerController->getDisplayId();
424 cursorPosition = pointerController->getPosition();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900425 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900426 if (mNotifiedPointerDisplayId == displayIdToNotify) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000427 return {};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900428 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900429 mNotifiedPointerDisplayId = displayIdToNotify;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000430 return {{displayIdToNotify, cursorPosition}};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900431}
432
433void PointerChoreographer::setDefaultMouseDisplayId(int32_t displayId) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000434 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900435
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000436 { // acquire lock
437 std::scoped_lock _l(mLock);
438
439 mDefaultMouseDisplayId = displayId;
440 pointerDisplayChange = updatePointerControllersLocked();
441 } // release lock
442
443 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900444}
445
446void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000447 PointerDisplayChange pointerDisplayChange;
448
449 { // acquire lock
450 std::scoped_lock _l(mLock);
451 for (const auto& viewport : viewports) {
452 const int32_t displayId = viewport.displayId;
453 if (const auto it = mMousePointersByDisplay.find(displayId);
454 it != mMousePointersByDisplay.end()) {
455 it->second->setDisplayViewport(viewport);
456 }
457 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
458 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
459 if (info && info->getAssociatedDisplayId() == displayId) {
460 stylusPointerController->setDisplayViewport(viewport);
461 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900462 }
463 }
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000464 mViewports = viewports;
465 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
466 } // release lock
467
468 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900469}
470
471std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
472 int32_t associatedDisplayId) {
473 std::scoped_lock _l(mLock);
474 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
475 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
476 return *viewport;
477 }
478 return std::nullopt;
479}
480
481FloatPoint PointerChoreographer::getMouseCursorPosition(int32_t displayId) {
482 std::scoped_lock _l(mLock);
483 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
484 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
485 it != mMousePointersByDisplay.end()) {
486 return it->second->getPosition();
487 }
488 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000489}
490
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900491void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000492 PointerDisplayChange pointerDisplayChange;
493
494 { // acquire lock
495 std::scoped_lock _l(mLock);
496 if (mShowTouchesEnabled == enabled) {
497 return;
498 }
499 mShowTouchesEnabled = enabled;
500 pointerDisplayChange = updatePointerControllersLocked();
501 } // release lock
502
503 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900504}
505
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900506void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000507 PointerDisplayChange pointerDisplayChange;
508
509 { // acquire lock
510 std::scoped_lock _l(mLock);
511 if (mStylusPointerIconEnabled == enabled) {
512 return;
513 }
514 mStylusPointerIconEnabled = enabled;
515 pointerDisplayChange = updatePointerControllersLocked();
516 } // release lock
517
518 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900519}
520
Byoungho Jung99326452023-11-03 20:19:17 +0900521bool PointerChoreographer::setPointerIcon(
522 std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId,
523 DeviceId deviceId) {
524 std::scoped_lock _l(mLock);
525 if (deviceId < 0) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000526 LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900527 return false;
528 }
529 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
530 if (!info) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000531 LOG(WARNING) << "No input device info found for id " << deviceId
532 << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900533 return false;
534 }
535 const uint32_t sources = info->getSources();
536 const auto stylusPointerIt = mStylusPointersByDevice.find(deviceId);
537
538 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) &&
539 stylusPointerIt != mStylusPointersByDevice.end()) {
540 if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
541 if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
542 LOG(FATAL) << "SpriteIcon should not be null";
543 }
544 stylusPointerIt->second->setCustomPointerIcon(
545 *std::get<std::unique_ptr<SpriteIcon>>(icon));
546 } else {
547 stylusPointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
548 }
549 } else if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
550 if (const auto mousePointerIt = mMousePointersByDisplay.find(displayId);
551 mousePointerIt != mMousePointersByDisplay.end()) {
552 if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
553 if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
554 LOG(FATAL) << "SpriteIcon should not be null";
555 }
556 mousePointerIt->second->setCustomPointerIcon(
557 *std::get<std::unique_ptr<SpriteIcon>>(icon));
558 } else {
559 mousePointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
560 }
561 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000562 LOG(WARNING) << "No mouse pointer controller found for display " << displayId
563 << ", device " << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900564 return false;
565 }
566 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000567 LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device "
568 << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900569 return false;
570 }
571 return true;
572}
573
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000574void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) {
575 std::scoped_lock lock(mLock);
576 if (visible) {
577 mDisplaysWithPointersHidden.erase(displayId);
578 // We do not unfade the icons here, because we don't know when the last event happened.
579 return;
580 }
581
582 mDisplaysWithPointersHidden.emplace(displayId);
583
584 // Hide any icons that are currently visible on the display.
585 if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
586 const auto& [_, controller] = *it;
587 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
588 }
589 for (const auto& [_, controller] : mStylusPointersByDevice) {
590 if (controller->getDisplayId() == displayId) {
591 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
592 }
593 }
594}
595
Prabir Pradhan19767602023-11-03 16:53:31 +0000596PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
597 int32_t displayId) {
598 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
599 [this, displayId]() REQUIRES(mLock) {
600 auto pc = mPolicy.createPointerController(
601 PointerControllerInterface::ControllerType::MOUSE);
602 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
603 pc->setDisplayViewport(*viewport);
604 }
605 return pc;
606 };
607 return ConstructorDelegate(std::move(ctor));
608}
609
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900610PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor(
611 int32_t displayId) {
612 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
613 [this, displayId]() REQUIRES(mLock) {
614 auto pc = mPolicy.createPointerController(
615 PointerControllerInterface::ControllerType::STYLUS);
616 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
617 pc->setDisplayViewport(*viewport);
618 }
619 return pc;
620 };
621 return ConstructorDelegate(std::move(ctor));
622}
623
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000624} // namespace android