blob: 916f8c6b5fcea86d3039c53ee3260beb870164e3 [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);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900125
126 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
127 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
128 pc.move(deltaX, deltaY);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000129 if (canUnfadeOnDisplay(displayId)) {
130 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
131 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900132
133 const auto [x, y] = pc.getPosition();
134 NotifyMotionArgs newArgs(args);
135 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
136 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
137 newArgs.xCursorPosition = x;
138 newArgs.yCursorPosition = y;
139 newArgs.displayId = displayId;
140 return newArgs;
141}
142
Byoungho Jungee6268f2023-10-30 17:27:26 +0900143NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
Prabir Pradhan990d8712024-03-05 00:31:36 +0000144 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900145
146 NotifyMotionArgs newArgs(args);
147 newArgs.displayId = displayId;
148 if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
149 // This is a movement of the mouse pointer.
150 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
151 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
152 pc.move(deltaX, deltaY);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000153 if (canUnfadeOnDisplay(displayId)) {
154 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
155 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900156
157 const auto [x, y] = pc.getPosition();
158 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
159 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
160 newArgs.xCursorPosition = x;
161 newArgs.yCursorPosition = y;
162 } else {
163 // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
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 for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
170 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
171 args.pointerCoords[i].getX() + x);
172 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
173 args.pointerCoords[i].getY() + y);
174 }
175 newArgs.xCursorPosition = x;
176 newArgs.yCursorPosition = y;
177 }
178 return newArgs;
179}
180
Byoungho Jungda10dd32023-10-06 17:03:45 +0900181/**
182 * When screen is touched, fade the mouse pointer on that display. We only call fade for
183 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
184 * mouse device keeps moving and unfades the cursor.
185 * For touch events, we do not need to populate the cursor position.
186 */
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900187void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) {
188 if (args.displayId == ADISPLAY_ID_NONE) {
189 return;
190 }
191
Byoungho Jungda10dd32023-10-06 17:03:45 +0900192 if (const auto it = mMousePointersByDisplay.find(args.displayId);
193 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
194 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
195 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900196
197 if (!mShowTouchesEnabled) {
198 return;
199 }
200
201 // Get the touch pointer controller for the device, or create one if it doesn't exist.
Prabir Pradhan16788792023-11-08 21:07:21 +0000202 auto [it, _] = mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900203
204 PointerControllerInterface& pc = *it->second;
205
206 const PointerCoords* coords = args.pointerCoords.data();
207 const int32_t maskedAction = MotionEvent::getActionMasked(args.action);
208 const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
209 std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
210 BitSet32 idBits;
211 if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL) {
212 for (size_t i = 0; i < args.getPointerCount(); i++) {
213 if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
214 continue;
215 }
216 uint32_t id = args.pointerProperties[i].id;
217 idToIndex[id] = i;
218 idBits.markBit(id);
219 }
220 }
221 // The PointerController already handles setting spots per-display, so
222 // we do not need to manually manage display changes for touch spots for now.
223 pc.setSpots(coords, idToIndex.cbegin(), idBits, args.displayId);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000224}
225
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900226void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& args) {
227 if (args.displayId == ADISPLAY_ID_NONE) {
228 return;
229 }
230
231 if (args.getPointerCount() != 1) {
232 LOG(WARNING) << "Only stylus hover events with a single pointer are currently supported: "
233 << args.dump();
234 }
235
236 // Get the stylus pointer controller for the device, or create one if it doesn't exist.
237 auto [it, _] =
238 mStylusPointersByDevice.try_emplace(args.deviceId,
239 getStylusControllerConstructor(args.displayId));
240
241 PointerControllerInterface& pc = *it->second;
242
243 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
244 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
245 pc.setPosition(x, y);
246 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
247 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhan4b36db92024-01-03 20:56:57 +0000248 pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000249 } else if (canUnfadeOnDisplay(args.displayId)) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900250 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
251 }
252}
253
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000254void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
255 mNextListener.notify(args);
256}
257
258void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
259 mNextListener.notify(args);
260}
261
262void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
263 mNextListener.notify(args);
264}
265
266void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900267 processDeviceReset(args);
268
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000269 mNextListener.notify(args);
270}
271
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900272void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) {
273 std::scoped_lock _l(mLock);
Prabir Pradhan16788792023-11-08 21:07:21 +0000274 mTouchPointersByDevice.erase(args.deviceId);
275 mStylusPointersByDevice.erase(args.deviceId);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900276}
277
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000278void PointerChoreographer::notifyPointerCaptureChanged(
279 const NotifyPointerCaptureChangedArgs& args) {
Hiroki Sato25040232024-02-22 17:21:22 +0900280 if (args.request.isEnable()) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900281 std::scoped_lock _l(mLock);
282 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
283 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
284 }
285 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000286 mNextListener.notify(args);
287}
288
289void PointerChoreographer::dump(std::string& dump) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900290 std::scoped_lock _l(mLock);
291
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000292 dump += "PointerChoreographer:\n";
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900293 dump += StringPrintf("show touches: %s\n", mShowTouchesEnabled ? "true" : "false");
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900294 dump += StringPrintf("stylus pointer icon enabled: %s\n",
295 mStylusPointerIconEnabled ? "true" : "false");
Byoungho Jungda10dd32023-10-06 17:03:45 +0900296
297 dump += INDENT "MousePointerControllers:\n";
298 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
299 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
300 dump += INDENT + std::to_string(displayId) + " : " + pointerControllerDump;
301 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900302 dump += INDENT "TouchPointerControllers:\n";
303 for (const auto& [deviceId, touchPointerController] : mTouchPointersByDevice) {
304 std::string pointerControllerDump = addLinePrefix(touchPointerController->dump(), INDENT);
305 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
306 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900307 dump += INDENT "StylusPointerControllers:\n";
308 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
309 std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
310 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
311 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900312 dump += "\n";
313}
314
315const DisplayViewport* PointerChoreographer::findViewportByIdLocked(int32_t displayId) const {
316 for (auto& viewport : mViewports) {
317 if (viewport.displayId == displayId) {
318 return &viewport;
319 }
320 }
321 return nullptr;
322}
323
324int32_t PointerChoreographer::getTargetMouseDisplayLocked(int32_t associatedDisplayId) const {
325 return associatedDisplayId == ADISPLAY_ID_NONE ? mDefaultMouseDisplayId : associatedDisplayId;
326}
327
Prabir Pradhan990d8712024-03-05 00:31:36 +0000328std::pair<int32_t, PointerControllerInterface&> PointerChoreographer::ensureMouseControllerLocked(
329 int32_t associatedDisplayId) {
Byoungho Jungee6268f2023-10-30 17:27:26 +0900330 const int32_t displayId = getTargetMouseDisplayLocked(associatedDisplayId);
331
Prabir Pradhan990d8712024-03-05 00:31:36 +0000332 auto it = mMousePointersByDisplay.find(displayId);
333 LOG_ALWAYS_FATAL_IF(it == mMousePointersByDisplay.end(),
334 "There is no mouse controller created for display %d", displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900335
336 return {displayId, *it->second};
337}
338
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900339InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000340 auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
341 [deviceId](const auto& info) { return info.getId() == deviceId; });
342 return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900343}
344
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000345bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) {
346 return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
347}
348
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000349PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900350 std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900351 std::set<DeviceId> touchDevicesToKeep;
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900352 std::set<DeviceId> stylusDevicesToKeep;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900353
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000354 // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
355 // new PointerControllers if necessary.
Byoungho Jungda10dd32023-10-06 17:03:45 +0900356 for (const auto& info : mInputDeviceInfos) {
357 const uint32_t sources = info.getSources();
358 if (isFromSource(sources, AINPUT_SOURCE_MOUSE) ||
359 isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000360 const int32_t displayId = getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
361 mouseDisplaysToKeep.insert(displayId);
362 // For mice, show the cursor immediately when the device is first connected or
363 // when it moves to a new display.
364 auto [mousePointerIt, isNewMousePointer] =
365 mMousePointersByDisplay.try_emplace(displayId,
366 getMouseControllerConstructor(displayId));
367 auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId());
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000368 if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000369 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
370 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900371 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900372 if (isFromSource(sources, AINPUT_SOURCE_TOUCHSCREEN) && mShowTouchesEnabled &&
373 info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) {
374 touchDevicesToKeep.insert(info.getId());
375 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900376 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && mStylusPointerIconEnabled &&
377 info.getAssociatedDisplayId() != ADISPLAY_ID_NONE) {
378 stylusDevicesToKeep.insert(info.getId());
379 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900380 }
381
382 // Remove PointerControllers no longer needed.
Prabir Pradhan19767602023-11-03 16:53:31 +0000383 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000384 return mouseDisplaysToKeep.find(pair.first) == mouseDisplaysToKeep.end();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900385 });
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900386 std::erase_if(mTouchPointersByDevice, [&touchDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000387 return touchDevicesToKeep.find(pair.first) == touchDevicesToKeep.end();
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900388 });
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900389 std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000390 return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900391 });
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000392 std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(mLock) {
393 return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
394 [id](const auto& info) { return info.getId() == id; }) ==
395 mInputDeviceInfos.end();
396 });
Byoungho Jungda10dd32023-10-06 17:03:45 +0900397
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000398 // Check if we need to notify the policy if there's a change on the pointer display ID.
399 return calculatePointerDisplayChangeToNotify();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900400}
401
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000402PointerChoreographer::PointerDisplayChange
403PointerChoreographer::calculatePointerDisplayChangeToNotify() {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900404 int32_t displayIdToNotify = ADISPLAY_ID_NONE;
405 FloatPoint cursorPosition = {0, 0};
406 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
407 it != mMousePointersByDisplay.end()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000408 const auto& pointerController = it->second;
409 // Use the displayId from the pointerController, because it accurately reflects whether
410 // the viewport has been added for that display. Otherwise, we would have to check if
411 // the viewport exists separately.
412 displayIdToNotify = pointerController->getDisplayId();
413 cursorPosition = pointerController->getPosition();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900414 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900415 if (mNotifiedPointerDisplayId == displayIdToNotify) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000416 return {};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900417 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900418 mNotifiedPointerDisplayId = displayIdToNotify;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000419 return {{displayIdToNotify, cursorPosition}};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900420}
421
422void PointerChoreographer::setDefaultMouseDisplayId(int32_t displayId) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000423 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900424
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000425 { // acquire lock
426 std::scoped_lock _l(mLock);
427
428 mDefaultMouseDisplayId = displayId;
429 pointerDisplayChange = updatePointerControllersLocked();
430 } // release lock
431
432 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900433}
434
435void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000436 PointerDisplayChange pointerDisplayChange;
437
438 { // acquire lock
439 std::scoped_lock _l(mLock);
440 for (const auto& viewport : viewports) {
441 const int32_t displayId = viewport.displayId;
442 if (const auto it = mMousePointersByDisplay.find(displayId);
443 it != mMousePointersByDisplay.end()) {
444 it->second->setDisplayViewport(viewport);
445 }
446 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
447 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
448 if (info && info->getAssociatedDisplayId() == displayId) {
449 stylusPointerController->setDisplayViewport(viewport);
450 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900451 }
452 }
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000453 mViewports = viewports;
454 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
455 } // release lock
456
457 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900458}
459
460std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
461 int32_t associatedDisplayId) {
462 std::scoped_lock _l(mLock);
463 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
464 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
465 return *viewport;
466 }
467 return std::nullopt;
468}
469
470FloatPoint PointerChoreographer::getMouseCursorPosition(int32_t displayId) {
471 std::scoped_lock _l(mLock);
472 const int32_t resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
473 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
474 it != mMousePointersByDisplay.end()) {
475 return it->second->getPosition();
476 }
477 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000478}
479
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900480void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000481 PointerDisplayChange pointerDisplayChange;
482
483 { // acquire lock
484 std::scoped_lock _l(mLock);
485 if (mShowTouchesEnabled == enabled) {
486 return;
487 }
488 mShowTouchesEnabled = enabled;
489 pointerDisplayChange = updatePointerControllersLocked();
490 } // release lock
491
492 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900493}
494
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900495void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000496 PointerDisplayChange pointerDisplayChange;
497
498 { // acquire lock
499 std::scoped_lock _l(mLock);
500 if (mStylusPointerIconEnabled == enabled) {
501 return;
502 }
503 mStylusPointerIconEnabled = enabled;
504 pointerDisplayChange = updatePointerControllersLocked();
505 } // release lock
506
507 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900508}
509
Byoungho Jung99326452023-11-03 20:19:17 +0900510bool PointerChoreographer::setPointerIcon(
511 std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId,
512 DeviceId deviceId) {
513 std::scoped_lock _l(mLock);
514 if (deviceId < 0) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000515 LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900516 return false;
517 }
518 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
519 if (!info) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000520 LOG(WARNING) << "No input device info found for id " << deviceId
521 << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900522 return false;
523 }
524 const uint32_t sources = info->getSources();
525 const auto stylusPointerIt = mStylusPointersByDevice.find(deviceId);
526
527 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) &&
528 stylusPointerIt != mStylusPointersByDevice.end()) {
529 if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
530 if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
531 LOG(FATAL) << "SpriteIcon should not be null";
532 }
533 stylusPointerIt->second->setCustomPointerIcon(
534 *std::get<std::unique_ptr<SpriteIcon>>(icon));
535 } else {
536 stylusPointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
537 }
538 } else if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
539 if (const auto mousePointerIt = mMousePointersByDisplay.find(displayId);
540 mousePointerIt != mMousePointersByDisplay.end()) {
541 if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
542 if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
543 LOG(FATAL) << "SpriteIcon should not be null";
544 }
545 mousePointerIt->second->setCustomPointerIcon(
546 *std::get<std::unique_ptr<SpriteIcon>>(icon));
547 } else {
548 mousePointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
549 }
550 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000551 LOG(WARNING) << "No mouse pointer controller found for display " << displayId
552 << ", device " << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900553 return false;
554 }
555 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000556 LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device "
557 << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900558 return false;
559 }
560 return true;
561}
562
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000563void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) {
564 std::scoped_lock lock(mLock);
565 if (visible) {
566 mDisplaysWithPointersHidden.erase(displayId);
567 // We do not unfade the icons here, because we don't know when the last event happened.
568 return;
569 }
570
571 mDisplaysWithPointersHidden.emplace(displayId);
572
573 // Hide any icons that are currently visible on the display.
574 if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
575 const auto& [_, controller] = *it;
576 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
577 }
578 for (const auto& [_, controller] : mStylusPointersByDevice) {
579 if (controller->getDisplayId() == displayId) {
580 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
581 }
582 }
583}
584
Prabir Pradhan19767602023-11-03 16:53:31 +0000585PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
586 int32_t displayId) {
587 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
588 [this, displayId]() REQUIRES(mLock) {
589 auto pc = mPolicy.createPointerController(
590 PointerControllerInterface::ControllerType::MOUSE);
591 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
592 pc->setDisplayViewport(*viewport);
593 }
594 return pc;
595 };
596 return ConstructorDelegate(std::move(ctor));
597}
598
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900599PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor(
600 int32_t displayId) {
601 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
602 [this, displayId]() REQUIRES(mLock) {
603 auto pc = mPolicy.createPointerController(
604 PointerControllerInterface::ControllerType::STYLUS);
605 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
606 pc->setDisplayViewport(*viewport);
607 }
608 return pc;
609 };
610 return ConstructorDelegate(std::move(ctor));
611}
612
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000613} // namespace android