blob: 3e7c1c71efbe2c26c22f70e368c3d54cf64b1bd2 [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
Byoungho Jungee6268f2023-10-30 17:27:26 +090034bool isFromTouchpad(const NotifyMotionArgs& args) {
35 return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
36 args.pointerProperties[0].toolType == ToolType::FINGER;
37}
38
Byoungho Jungd6fe27b2023-10-27 20:49:38 +090039bool isHoverAction(int32_t action) {
40 return action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
41 action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT;
42}
43
44bool isStylusHoverEvent(const NotifyMotionArgs& args) {
45 return isStylusEvent(args.source, args.pointerProperties) && isHoverAction(args.action);
46}
Byoungho Jungda10dd32023-10-06 17:03:45 +090047} // namespace
48
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000049// --- PointerChoreographer ---
50
51PointerChoreographer::PointerChoreographer(InputListenerInterface& listener,
52 PointerChoreographerPolicyInterface& policy)
Prabir Pradhan16788792023-11-08 21:07:21 +000053 : mTouchControllerConstructor([this]() REQUIRES(mLock) {
54 return mPolicy.createPointerController(
55 PointerControllerInterface::ControllerType::TOUCH);
56 }),
57 mNextListener(listener),
Byoungho Jungda10dd32023-10-06 17:03:45 +090058 mPolicy(policy),
59 mDefaultMouseDisplayId(ADISPLAY_ID_DEFAULT),
Byoungho Jung6f5b16b2023-10-27 18:22:07 +090060 mNotifiedPointerDisplayId(ADISPLAY_ID_NONE),
Byoungho Jungd6fe27b2023-10-27 20:49:38 +090061 mShowTouchesEnabled(false),
62 mStylusPointerIconEnabled(false) {}
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000063
64void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +090065 std::scoped_lock _l(mLock);
66
67 mInputDeviceInfos = args.inputDeviceInfos;
68 updatePointerControllersLocked();
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000069 mNextListener.notify(args);
70}
71
72void PointerChoreographer::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) {
73 mNextListener.notify(args);
74}
75
76void PointerChoreographer::notifyKey(const NotifyKeyArgs& args) {
77 mNextListener.notify(args);
78}
79
80void PointerChoreographer::notifyMotion(const NotifyMotionArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +090081 NotifyMotionArgs newArgs = processMotion(args);
82
83 mNextListener.notify(newArgs);
84}
85
86NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& args) {
87 std::scoped_lock _l(mLock);
88
89 if (isFromMouse(args)) {
90 return processMouseEventLocked(args);
Byoungho Jungee6268f2023-10-30 17:27:26 +090091 } else if (isFromTouchpad(args)) {
92 return processTouchpadEventLocked(args);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +090093 } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
94 processStylusHoverEventLocked(args);
Byoungho Jungda10dd32023-10-06 17:03:45 +090095 } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +090096 processTouchscreenAndStylusEventLocked(args);
Byoungho Jungda10dd32023-10-06 17:03:45 +090097 }
98 return args;
99}
100
101NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotionArgs& args) {
102 if (args.getPointerCount() != 1) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000103 LOG(FATAL) << "Only mouse events with a single pointer are currently supported: "
104 << args.dump();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900105 }
106
Prabir Pradhan990d8712024-03-05 00:31:36 +0000107 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900108
109 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
110 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
111 pc.move(deltaX, deltaY);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000112 if (canUnfadeOnDisplay(displayId)) {
113 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
114 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900115
116 const auto [x, y] = pc.getPosition();
117 NotifyMotionArgs newArgs(args);
118 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
119 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
120 newArgs.xCursorPosition = x;
121 newArgs.yCursorPosition = y;
122 newArgs.displayId = displayId;
123 return newArgs;
124}
125
Byoungho Jungee6268f2023-10-30 17:27:26 +0900126NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
Prabir Pradhan990d8712024-03-05 00:31:36 +0000127 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900128
129 NotifyMotionArgs newArgs(args);
130 newArgs.displayId = displayId;
131 if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
132 // This is a movement of the mouse pointer.
133 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
134 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
135 pc.move(deltaX, deltaY);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000136 if (canUnfadeOnDisplay(displayId)) {
137 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
138 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900139
140 const auto [x, y] = pc.getPosition();
141 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
142 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
143 newArgs.xCursorPosition = x;
144 newArgs.yCursorPosition = y;
145 } else {
146 // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000147 if (canUnfadeOnDisplay(displayId)) {
148 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
149 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900150
151 const auto [x, y] = pc.getPosition();
152 for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
153 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
154 args.pointerCoords[i].getX() + x);
155 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
156 args.pointerCoords[i].getY() + y);
157 }
158 newArgs.xCursorPosition = x;
159 newArgs.yCursorPosition = y;
160 }
161 return newArgs;
162}
163
Byoungho Jungda10dd32023-10-06 17:03:45 +0900164/**
165 * When screen is touched, fade the mouse pointer on that display. We only call fade for
166 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
167 * mouse device keeps moving and unfades the cursor.
168 * For touch events, we do not need to populate the cursor position.
169 */
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900170void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) {
171 if (args.displayId == ADISPLAY_ID_NONE) {
172 return;
173 }
174
Byoungho Jungda10dd32023-10-06 17:03:45 +0900175 if (const auto it = mMousePointersByDisplay.find(args.displayId);
176 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
177 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
178 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900179
180 if (!mShowTouchesEnabled) {
181 return;
182 }
183
184 // Get the touch pointer controller for the device, or create one if it doesn't exist.
Prabir Pradhan16788792023-11-08 21:07:21 +0000185 auto [it, _] = mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900186
187 PointerControllerInterface& pc = *it->second;
188
189 const PointerCoords* coords = args.pointerCoords.data();
190 const int32_t maskedAction = MotionEvent::getActionMasked(args.action);
191 const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
192 std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
193 BitSet32 idBits;
194 if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL) {
195 for (size_t i = 0; i < args.getPointerCount(); i++) {
196 if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
197 continue;
198 }
199 uint32_t id = args.pointerProperties[i].id;
200 idToIndex[id] = i;
201 idBits.markBit(id);
202 }
203 }
204 // The PointerController already handles setting spots per-display, so
205 // we do not need to manually manage display changes for touch spots for now.
206 pc.setSpots(coords, idToIndex.cbegin(), idBits, args.displayId);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000207}
208
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900209void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& args) {
210 if (args.displayId == ADISPLAY_ID_NONE) {
211 return;
212 }
213
214 if (args.getPointerCount() != 1) {
215 LOG(WARNING) << "Only stylus hover events with a single pointer are currently supported: "
216 << args.dump();
217 }
218
219 // Get the stylus pointer controller for the device, or create one if it doesn't exist.
220 auto [it, _] =
221 mStylusPointersByDevice.try_emplace(args.deviceId,
222 getStylusControllerConstructor(args.displayId));
223
224 PointerControllerInterface& pc = *it->second;
225
226 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
227 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
228 pc.setPosition(x, y);
229 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
230 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhan4b36db92024-01-03 20:56:57 +0000231 pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000232 } else if (canUnfadeOnDisplay(args.displayId)) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900233 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
234 }
235}
236
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000237void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
238 mNextListener.notify(args);
239}
240
241void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
242 mNextListener.notify(args);
243}
244
245void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
246 mNextListener.notify(args);
247}
248
249void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900250 processDeviceReset(args);
251
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000252 mNextListener.notify(args);
253}
254
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900255void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) {
256 std::scoped_lock _l(mLock);
Prabir Pradhan16788792023-11-08 21:07:21 +0000257 mTouchPointersByDevice.erase(args.deviceId);
258 mStylusPointersByDevice.erase(args.deviceId);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900259}
260
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000261void PointerChoreographer::notifyPointerCaptureChanged(
262 const NotifyPointerCaptureChangedArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900263 if (args.request.enable) {
264 std::scoped_lock _l(mLock);
265 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
266 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
267 }
268 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000269 mNextListener.notify(args);
270}
271
272void PointerChoreographer::dump(std::string& dump) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900273 std::scoped_lock _l(mLock);
274
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000275 dump += "PointerChoreographer:\n";
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900276 dump += StringPrintf("show touches: %s\n", mShowTouchesEnabled ? "true" : "false");
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900277 dump += StringPrintf("stylus pointer icon enabled: %s\n",
278 mStylusPointerIconEnabled ? "true" : "false");
Byoungho Jungda10dd32023-10-06 17:03:45 +0900279
280 dump += INDENT "MousePointerControllers:\n";
281 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
282 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
283 dump += INDENT + std::to_string(displayId) + " : " + pointerControllerDump;
284 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900285 dump += INDENT "TouchPointerControllers:\n";
286 for (const auto& [deviceId, touchPointerController] : mTouchPointersByDevice) {
287 std::string pointerControllerDump = addLinePrefix(touchPointerController->dump(), INDENT);
288 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
289 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900290 dump += INDENT "StylusPointerControllers:\n";
291 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
292 std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
293 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
294 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900295 dump += "\n";
296}
297
298const DisplayViewport* PointerChoreographer::findViewportByIdLocked(int32_t displayId) const {
299 for (auto& viewport : mViewports) {
300 if (viewport.displayId == displayId) {
301 return &viewport;
302 }
303 }
304 return nullptr;
305}
306
307int32_t PointerChoreographer::getTargetMouseDisplayLocked(int32_t associatedDisplayId) const {
308 return associatedDisplayId == ADISPLAY_ID_NONE ? mDefaultMouseDisplayId : associatedDisplayId;
309}
310
Prabir Pradhan990d8712024-03-05 00:31:36 +0000311std::pair<int32_t, PointerControllerInterface&> PointerChoreographer::ensureMouseControllerLocked(
312 int32_t associatedDisplayId) {
Byoungho Jungee6268f2023-10-30 17:27:26 +0900313 const int32_t displayId = getTargetMouseDisplayLocked(associatedDisplayId);
314
Prabir Pradhan990d8712024-03-05 00:31:36 +0000315 auto it = mMousePointersByDisplay.find(displayId);
316 LOG_ALWAYS_FATAL_IF(it == mMousePointersByDisplay.end(),
317 "There is no mouse controller created for display %d", displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900318
319 return {displayId, *it->second};
320}
321
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900322InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000323 auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
324 [deviceId](const auto& info) { return info.getId() == deviceId; });
325 return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900326}
327
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000328bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) {
329 return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
330}
331
Byoungho Jungda10dd32023-10-06 17:03:45 +0900332void PointerChoreographer::updatePointerControllersLocked() {
333 std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900334 std::set<DeviceId> touchDevicesToKeep;
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900335 std::set<DeviceId> stylusDevicesToKeep;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900336
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000337 // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
338 // new PointerControllers if necessary.
Byoungho Jungda10dd32023-10-06 17:03:45 +0900339 for (const auto& info : mInputDeviceInfos) {
340 const uint32_t sources = info.getSources();
341 if (isFromSource(sources, AINPUT_SOURCE_MOUSE) ||
342 isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000343 const int32_t displayId = getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
344 mouseDisplaysToKeep.insert(displayId);
345 // For mice, show the cursor immediately when the device is first connected or
346 // when it moves to a new display.
347 auto [mousePointerIt, isNewMousePointer] =
348 mMousePointersByDisplay.try_emplace(displayId,
349 getMouseControllerConstructor(displayId));
350 auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId());
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000351 if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000352 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
353 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900354 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900355 if (isFromSource(sources, AINPUT_SOURCE_TOUCHSCREEN) && mShowTouchesEnabled &&
356 info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) {
357 touchDevicesToKeep.insert(info.getId());
358 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900359 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && mStylusPointerIconEnabled &&
360 info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) {
361 stylusDevicesToKeep.insert(info.getId());
362 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900363 }
364
365 // Remove PointerControllers no longer needed.
Prabir Pradhan19767602023-11-03 16:53:31 +0000366 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000367 return mouseDisplaysToKeep.find(pair.first) == mouseDisplaysToKeep.end();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900368 });
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900369 std::erase_if(mTouchPointersByDevice, [&touchDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000370 return touchDevicesToKeep.find(pair.first) == touchDevicesToKeep.end();
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900371 });
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900372 std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000373 return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900374 });
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000375 std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(mLock) {
376 return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
377 [id](const auto& info) { return info.getId() == id; }) ==
378 mInputDeviceInfos.end();
379 });
Byoungho Jungda10dd32023-10-06 17:03:45 +0900380
381 // Notify the policy if there's a change on the pointer display ID.
382 notifyPointerDisplayIdChangedLocked();
383}
384
385void PointerChoreographer::notifyPointerDisplayIdChangedLocked() {
386 int32_t displayIdToNotify = ADISPLAY_ID_NONE;
387 FloatPoint cursorPosition = {0, 0};
388 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
389 it != mMousePointersByDisplay.end()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000390 const auto& pointerController = it->second;
391 // Use the displayId from the pointerController, because it accurately reflects whether
392 // the viewport has been added for that display. Otherwise, we would have to check if
393 // the viewport exists separately.
394 displayIdToNotify = pointerController->getDisplayId();
395 cursorPosition = pointerController->getPosition();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900396 }
397
398 if (mNotifiedPointerDisplayId == displayIdToNotify) {
399 return;
400 }
401 mPolicy.notifyPointerDisplayIdChanged(displayIdToNotify, cursorPosition);
402 mNotifiedPointerDisplayId = displayIdToNotify;
403}
404
405void PointerChoreographer::setDefaultMouseDisplayId(int32_t displayId) {
406 std::scoped_lock _l(mLock);
407
408 mDefaultMouseDisplayId = displayId;
409 updatePointerControllersLocked();
410}
411
412void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
413 std::scoped_lock _l(mLock);
414 for (const auto& viewport : viewports) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900415 const int32_t displayId = viewport.displayId;
416 if (const auto it = mMousePointersByDisplay.find(displayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900417 it != mMousePointersByDisplay.end()) {
418 it->second->setDisplayViewport(viewport);
419 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900420 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
421 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
422 if (info && info->getAssociatedDisplayId() == displayId) {
423 stylusPointerController->setDisplayViewport(viewport);
424 }
425 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900426 }
427 mViewports = viewports;
428 notifyPointerDisplayIdChangedLocked();
429}
430
431std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
432 int32_t associatedDisplayId) {
433 std::scoped_lock _l(mLock);
434 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
435 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
436 return *viewport;
437 }
438 return std::nullopt;
439}
440
441FloatPoint PointerChoreographer::getMouseCursorPosition(int32_t displayId) {
442 std::scoped_lock _l(mLock);
443 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
444 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
445 it != mMousePointersByDisplay.end()) {
446 return it->second->getPosition();
447 }
448 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000449}
450
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900451void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
452 std::scoped_lock _l(mLock);
453 if (mShowTouchesEnabled == enabled) {
454 return;
455 }
456 mShowTouchesEnabled = enabled;
457 updatePointerControllersLocked();
458}
459
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900460void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
461 std::scoped_lock _l(mLock);
462 if (mStylusPointerIconEnabled == enabled) {
463 return;
464 }
465 mStylusPointerIconEnabled = enabled;
466 updatePointerControllersLocked();
467}
468
Byoungho Jung99326452023-11-03 20:19:17 +0900469bool PointerChoreographer::setPointerIcon(
470 std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId,
471 DeviceId deviceId) {
472 std::scoped_lock _l(mLock);
473 if (deviceId < 0) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000474 LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900475 return false;
476 }
477 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
478 if (!info) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000479 LOG(WARNING) << "No input device info found for id " << deviceId
480 << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900481 return false;
482 }
483 const uint32_t sources = info->getSources();
484 const auto stylusPointerIt = mStylusPointersByDevice.find(deviceId);
485
486 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) &&
487 stylusPointerIt != mStylusPointersByDevice.end()) {
488 if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
489 if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
490 LOG(FATAL) << "SpriteIcon should not be null";
491 }
492 stylusPointerIt->second->setCustomPointerIcon(
493 *std::get<std::unique_ptr<SpriteIcon>>(icon));
494 } else {
495 stylusPointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
496 }
497 } else if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
498 if (const auto mousePointerIt = mMousePointersByDisplay.find(displayId);
499 mousePointerIt != mMousePointersByDisplay.end()) {
500 if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
501 if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
502 LOG(FATAL) << "SpriteIcon should not be null";
503 }
504 mousePointerIt->second->setCustomPointerIcon(
505 *std::get<std::unique_ptr<SpriteIcon>>(icon));
506 } else {
507 mousePointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
508 }
509 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000510 LOG(WARNING) << "No mouse pointer controller found for display " << displayId
511 << ", device " << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900512 return false;
513 }
514 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000515 LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device "
516 << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900517 return false;
518 }
519 return true;
520}
521
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000522void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) {
523 std::scoped_lock lock(mLock);
524 if (visible) {
525 mDisplaysWithPointersHidden.erase(displayId);
526 // We do not unfade the icons here, because we don't know when the last event happened.
527 return;
528 }
529
530 mDisplaysWithPointersHidden.emplace(displayId);
531
532 // Hide any icons that are currently visible on the display.
533 if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
534 const auto& [_, controller] = *it;
535 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
536 }
537 for (const auto& [_, controller] : mStylusPointersByDevice) {
538 if (controller->getDisplayId() == displayId) {
539 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
540 }
541 }
542}
543
Prabir Pradhan19767602023-11-03 16:53:31 +0000544PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
545 int32_t displayId) {
546 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
547 [this, displayId]() REQUIRES(mLock) {
548 auto pc = mPolicy.createPointerController(
549 PointerControllerInterface::ControllerType::MOUSE);
550 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
551 pc->setDisplayViewport(*viewport);
552 }
553 return pc;
554 };
555 return ConstructorDelegate(std::move(ctor));
556}
557
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900558PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor(
559 int32_t displayId) {
560 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
561 [this, displayId]() REQUIRES(mLock) {
562 auto pc = mPolicy.createPointerController(
563 PointerControllerInterface::ControllerType::STYLUS);
564 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
565 pc->setDisplayViewport(*viewport);
566 }
567 return pc;
568 };
569 return ConstructorDelegate(std::move(ctor));
570}
571
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000572} // namespace android