blob: 811692f1bf73e41a59e569b40e8130b74fe5341c [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>
Arpit Singh4b6ad2d2024-04-04 11:54:20 +000020#include <com_android_input_flags.h>
21#if defined(__ANDROID__)
22#include <gui/SurfaceComposerClient.h>
23#endif
Arpit Singhb65e2bd2024-06-03 09:48:16 +000024#include <input/Keyboard.h>
Byoungho Jungda10dd32023-10-06 17:03:45 +090025#include <input/PrintTools.h>
Arpit Singh4b6ad2d2024-04-04 11:54:20 +000026#include <unordered_set>
Byoungho Jungda10dd32023-10-06 17:03:45 +090027
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000028#include "PointerChoreographer.h"
29
Byoungho Jungda10dd32023-10-06 17:03:45 +090030#define INDENT " "
31
Prabir Pradhanb56e92c2023-06-09 23:40:37 +000032namespace android {
33
Byoungho Jungda10dd32023-10-06 17:03:45 +090034namespace {
Prabir Pradhan5a51a222024-03-05 03:54:00 +000035
Byoungho Jungda10dd32023-10-06 17:03:45 +090036bool isFromMouse(const NotifyMotionArgs& args) {
37 return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
38 args.pointerProperties[0].toolType == ToolType::MOUSE;
39}
40
Byoungho Jungee6268f2023-10-30 17:27:26 +090041bool isFromTouchpad(const NotifyMotionArgs& args) {
42 return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
43 args.pointerProperties[0].toolType == ToolType::FINGER;
44}
45
Prabir Pradhan4c977a42024-03-15 16:47:37 +000046bool isFromDrawingTablet(const NotifyMotionArgs& args) {
47 return isFromSource(args.source, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS) &&
48 isStylusToolType(args.pointerProperties[0].toolType);
49}
50
Byoungho Jungd6fe27b2023-10-27 20:49:38 +090051bool isHoverAction(int32_t action) {
52 return action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
53 action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT;
54}
55
56bool isStylusHoverEvent(const NotifyMotionArgs& args) {
57 return isStylusEvent(args.source, args.pointerProperties) && isHoverAction(args.action);
58}
Prabir Pradhan5a51a222024-03-05 03:54:00 +000059
Prabir Pradhan4c977a42024-03-15 16:47:37 +000060bool isMouseOrTouchpad(uint32_t sources) {
61 // Check if this is a mouse or touchpad, but not a drawing tablet.
62 return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
63 (isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
64 !isFromSource(sources, AINPUT_SOURCE_STYLUS));
65}
66
Arpit Singh7f21fa32024-11-26 15:44:26 +000067inline void notifyPointerDisplayChange(std::optional<std::tuple<ui::LogicalDisplayId, vec2>> change,
68 PointerChoreographerPolicyInterface& policy) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +000069 if (!change) {
70 return;
71 }
72 const auto& [displayId, cursorPosition] = *change;
73 policy.notifyPointerDisplayIdChanged(displayId, cursorPosition);
74}
75
Prabir Pradhan4c977a42024-03-15 16:47:37 +000076void setIconForController(const std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle>& icon,
77 PointerControllerInterface& controller) {
78 if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
79 if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
80 LOG(FATAL) << "SpriteIcon should not be null";
81 }
82 controller.setCustomPointerIcon(*std::get<std::unique_ptr<SpriteIcon>>(icon));
83 } else {
84 controller.updatePointerIcon(std::get<PointerIconStyle>(icon));
85 }
86}
87
Arpit Singh420d0742024-04-04 11:54:20 +000088// filters and returns a set of privacy sensitive displays that are currently visible.
89std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysFromWindowInfos(
90 const std::vector<gui::WindowInfo>& windowInfos) {
91 std::unordered_set<ui::LogicalDisplayId> privacySensitiveDisplays;
92 for (const auto& windowInfo : windowInfos) {
93 if (!windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE) &&
94 windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY)) {
95 privacySensitiveDisplays.insert(windowInfo.displayId);
96 }
97 }
98 return privacySensitiveDisplays;
99}
100
Byoungho Jungda10dd32023-10-06 17:03:45 +0900101} // namespace
102
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000103// --- PointerChoreographer ---
104
Arpit Singhbd49b282024-05-23 18:02:54 +0000105PointerChoreographer::PointerChoreographer(InputListenerInterface& inputListener,
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000106 PointerChoreographerPolicyInterface& policy)
Arpit Singhbd49b282024-05-23 18:02:54 +0000107 : PointerChoreographer(
108 inputListener, policy,
109 [](const sp<android::gui::WindowInfosListener>& listener) {
110 auto initialInfo = std::make_pair(std::vector<android::gui::WindowInfo>{},
111 std::vector<android::gui::DisplayInfo>{});
112#if defined(__ANDROID__)
113 SurfaceComposerClient::getDefault()->addWindowInfosListener(listener,
114 &initialInfo);
115#endif
116 return initialInfo.first;
117 },
118 [](const sp<android::gui::WindowInfosListener>& listener) {
119#if defined(__ANDROID__)
120 SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
121#endif
122 }) {
123}
124
125PointerChoreographer::PointerChoreographer(
126 android::InputListenerInterface& listener,
127 android::PointerChoreographerPolicyInterface& policy,
128 const android::PointerChoreographer::WindowListenerRegisterConsumer& registerListener,
129 const android::PointerChoreographer::WindowListenerUnregisterConsumer& unregisterListener)
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000130 : mTouchControllerConstructor([this]() {
Prabir Pradhan16788792023-11-08 21:07:21 +0000131 return mPolicy.createPointerController(
132 PointerControllerInterface::ControllerType::TOUCH);
133 }),
134 mNextListener(listener),
Byoungho Jungda10dd32023-10-06 17:03:45 +0900135 mPolicy(policy),
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700136 mDefaultMouseDisplayId(ui::LogicalDisplayId::DEFAULT),
137 mNotifiedPointerDisplayId(ui::LogicalDisplayId::INVALID),
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900138 mShowTouchesEnabled(false),
Arpit Singhbd49b282024-05-23 18:02:54 +0000139 mStylusPointerIconEnabled(false),
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000140 mCurrentFocusedDisplay(ui::LogicalDisplayId::DEFAULT),
Arpit Singh7918c822024-11-20 11:28:44 +0000141 mIsWindowInfoListenerRegistered(false),
142 mWindowInfoListener(sp<PointerChoreographerDisplayInfoListener>::make(this)),
Arpit Singhbd49b282024-05-23 18:02:54 +0000143 mRegisterListener(registerListener),
144 mUnregisterListener(unregisterListener) {}
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000145
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000146PointerChoreographer::~PointerChoreographer() {
Arpit Singh7918c822024-11-20 11:28:44 +0000147 if (mIsWindowInfoListenerRegistered) {
148 mUnregisterListener(mWindowInfoListener);
149 mIsWindowInfoListenerRegistered = false;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000150 }
151 mWindowInfoListener->onPointerChoreographerDestroyed();
152}
153
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000154void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000155 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900156
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000157 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000158 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000159
160 mInputDeviceInfos = args.inputDeviceInfos;
161 pointerDisplayChange = updatePointerControllersLocked();
162 } // release lock
163
164 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000165 mNextListener.notify(args);
166}
167
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000168void PointerChoreographer::notifyKey(const NotifyKeyArgs& args) {
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000169 fadeMouseCursorOnKeyPress(args);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000170 mNextListener.notify(args);
171}
172
173void PointerChoreographer::notifyMotion(const NotifyMotionArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900174 NotifyMotionArgs newArgs = processMotion(args);
175
176 mNextListener.notify(newArgs);
177}
178
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000179void PointerChoreographer::fadeMouseCursorOnKeyPress(const android::NotifyKeyArgs& args) {
180 if (args.action == AKEY_EVENT_ACTION_UP || isMetaKey(args.keyCode)) {
181 return;
182 }
183 // Meta state for these keys is ignored for dismissing cursor while typing
184 constexpr static int32_t ALLOW_FADING_META_STATE_MASK = AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON |
185 AMETA_SCROLL_LOCK_ON | AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON | AMETA_SHIFT_ON;
186 if (args.metaState & ~ALLOW_FADING_META_STATE_MASK) {
187 // Do not fade if any other meta state is active
188 return;
189 }
190 if (!mPolicy.isInputMethodConnectionActive()) {
191 return;
192 }
193
Arpit Singh7918c822024-11-20 11:28:44 +0000194 std::scoped_lock _l(getLock());
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000195 ui::LogicalDisplayId targetDisplay = args.displayId;
196 if (targetDisplay == ui::LogicalDisplayId::INVALID) {
197 targetDisplay = mCurrentFocusedDisplay;
198 }
199 auto it = mMousePointersByDisplay.find(targetDisplay);
200 if (it != mMousePointersByDisplay.end()) {
Arpit Singh849beb42024-06-06 07:14:17 +0000201 mPolicy.notifyMouseCursorFadedOnTyping();
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000202 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
203 }
204}
205
Byoungho Jungda10dd32023-10-06 17:03:45 +0900206NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& args) {
Arpit Singhe33845c2024-10-25 20:59:24 +0000207 NotifyMotionArgs newArgs(args);
208 PointerDisplayChange pointerDisplayChange;
209 { // acquire lock
210 std::scoped_lock _l(getLock());
211 if (isFromMouse(args)) {
212 newArgs = processMouseEventLocked(args);
213 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
214 } else if (isFromTouchpad(args)) {
215 newArgs = processTouchpadEventLocked(args);
216 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
217 } else if (isFromDrawingTablet(args)) {
218 processDrawingTabletEventLocked(args);
219 } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
220 processStylusHoverEventLocked(args);
221 } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
222 processTouchscreenAndStylusEventLocked(args);
223 }
224 } // release lock
Byoungho Jungda10dd32023-10-06 17:03:45 +0900225
Arpit Singhe33845c2024-10-25 20:59:24 +0000226 if (pointerDisplayChange) {
227 // pointer display may have changed if mouse crossed display boundary
228 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900229 }
Arpit Singhe33845c2024-10-25 20:59:24 +0000230 return newArgs;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900231}
232
233NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotionArgs& args) {
234 if (args.getPointerCount() != 1) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000235 LOG(FATAL) << "Only mouse events with a single pointer are currently supported: "
236 << args.dump();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900237 }
238
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000239 mMouseDevices.emplace(args.deviceId);
Prabir Pradhan990d8712024-03-05 00:31:36 +0000240 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900241 NotifyMotionArgs newArgs(args);
242 newArgs.displayId = displayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900243
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900244 if (MotionEvent::isValidCursorPosition(args.xCursorPosition, args.yCursorPosition)) {
245 // This is an absolute mouse device that knows about the location of the cursor on the
246 // display, so set the cursor position to the specified location.
Arpit Singh7f21fa32024-11-26 15:44:26 +0000247 const auto position = pc.getPosition();
248 const float deltaX = args.xCursorPosition - position.x;
249 const float deltaY = args.yCursorPosition - position.y;
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900250 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
251 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
252 pc.setPosition(args.xCursorPosition, args.yCursorPosition);
253 } else {
254 // This is a relative mouse, so move the cursor by the specified amount.
Arpit Singh5cd74972024-11-25 11:17:42 +0000255 processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc);
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900256 }
Arpit Singhe33845c2024-10-25 20:59:24 +0000257 // Note displayId may have changed if the cursor moved to a different display
258 if (canUnfadeOnDisplay(newArgs.displayId)) {
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000259 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
260 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900261 return newArgs;
262}
263
Byoungho Jungee6268f2023-10-30 17:27:26 +0900264NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000265 mMouseDevices.emplace(args.deviceId);
Prabir Pradhan990d8712024-03-05 00:31:36 +0000266 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900267
268 NotifyMotionArgs newArgs(args);
269 newArgs.displayId = displayId;
270 if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
271 // This is a movement of the mouse pointer.
Arpit Singh5cd74972024-11-25 11:17:42 +0000272 processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900273 } else {
274 // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
Arpit Singh7f21fa32024-11-26 15:44:26 +0000275 const auto position = pc.getPosition();
Byoungho Jungee6268f2023-10-30 17:27:26 +0900276 for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
277 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
Arpit Singh7f21fa32024-11-26 15:44:26 +0000278 args.pointerCoords[i].getX() + position.x);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900279 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
Arpit Singh7f21fa32024-11-26 15:44:26 +0000280 args.pointerCoords[i].getY() + position.y);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900281 }
Arpit Singh7f21fa32024-11-26 15:44:26 +0000282 newArgs.xCursorPosition = position.x;
283 newArgs.yCursorPosition = position.y;
Byoungho Jungee6268f2023-10-30 17:27:26 +0900284 }
Arpit Singhe33845c2024-10-25 20:59:24 +0000285
286 // Note displayId may have changed if the cursor moved to a different display
287 if (canUnfadeOnDisplay(newArgs.displayId)) {
Arpit Singh5cd74972024-11-25 11:17:42 +0000288 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
289 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900290 return newArgs;
291}
292
Arpit Singh5cd74972024-11-25 11:17:42 +0000293void PointerChoreographer::processPointerDeviceMotionEventLocked(NotifyMotionArgs& newArgs,
294 PointerControllerInterface& pc) {
295 const float deltaX = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
296 const float deltaY = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
297
Arpit Singh7f21fa32024-11-26 15:44:26 +0000298 vec2 unconsumedDelta = pc.move(deltaX, deltaY);
Arpit Singhe33845c2024-10-25 20:59:24 +0000299 if (com::android::input::flags::connected_displays_cursor() &&
300 (std::abs(unconsumedDelta.x) > 0 || std::abs(unconsumedDelta.y) > 0)) {
301 handleUnconsumedDeltaLocked(pc, unconsumedDelta);
302 // pointer may have moved to a different viewport
303 newArgs.displayId = pc.getDisplayId();
304 }
305
Arpit Singh7f21fa32024-11-26 15:44:26 +0000306 const auto position = pc.getPosition();
307 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, position.x);
308 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, position.y);
309 newArgs.xCursorPosition = position.x;
310 newArgs.yCursorPosition = position.y;
Arpit Singh5cd74972024-11-25 11:17:42 +0000311}
312
Arpit Singhe33845c2024-10-25 20:59:24 +0000313void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterface& pc,
Arpit Singh7f21fa32024-11-26 15:44:26 +0000314 const vec2& unconsumedDelta) {
Arpit Singhf0169ab2024-11-18 20:44:35 +0000315 // Display topology is in rotated coordinate space and Pointer controller returns and expects
316 // values in the un-rotated coordinate space. So we need to transform delta and cursor position
317 // back to the rotated coordinate space to lookup adjacent display in the display topology.
318 const auto& sourceDisplayTransform = pc.getDisplayTransform();
319 const vec2 rotatedUnconsumedDelta =
Arpit Singh7f21fa32024-11-26 15:44:26 +0000320 transformWithoutTranslation(sourceDisplayTransform, unconsumedDelta);
321 const vec2 cursorPosition = pc.getPosition();
322 const vec2 rotatedCursorPosition = sourceDisplayTransform.transform(cursorPosition);
Arpit Singhf0169ab2024-11-18 20:44:35 +0000323
324 // To find out the boundary that cursor is crossing we are checking delta in x and y direction
325 // respectively. This prioritizes x direction over y.
326 // In practise, majority of cases we only have non-zero values in either x or y coordinates,
327 // except sometimes near the corners.
328 // In these cases this behaviour is not noticeable. We also do not apply unconsumed delta on
329 // the destination display for the same reason.
330 DisplayPosition sourceBoundary;
331 float cursorOffset = 0.0f;
332 if (rotatedUnconsumedDelta.x > 0) {
333 sourceBoundary = DisplayPosition::RIGHT;
334 cursorOffset = rotatedCursorPosition.y;
335 } else if (rotatedUnconsumedDelta.x < 0) {
336 sourceBoundary = DisplayPosition::LEFT;
337 cursorOffset = rotatedCursorPosition.y;
338 } else if (rotatedUnconsumedDelta.y > 0) {
339 sourceBoundary = DisplayPosition::BOTTOM;
340 cursorOffset = rotatedCursorPosition.x;
341 } else {
342 sourceBoundary = DisplayPosition::TOP;
343 cursorOffset = rotatedCursorPosition.x;
344 }
345
Arpit Singhe33845c2024-10-25 20:59:24 +0000346 const ui::LogicalDisplayId sourceDisplayId = pc.getDisplayId();
Arpit Singhf0169ab2024-11-18 20:44:35 +0000347 std::optional<std::pair<const DisplayViewport*, float /*offset*/>> destination =
348 findDestinationDisplayLocked(sourceDisplayId, sourceBoundary, cursorOffset);
349 if (!destination.has_value()) {
350 // No matching adjacent display
Arpit Singhe33845c2024-10-25 20:59:24 +0000351 return;
352 }
353
Arpit Singhf0169ab2024-11-18 20:44:35 +0000354 const DisplayViewport& destinationViewport = *destination->first;
355 const float destinationOffset = destination->second;
356 if (mMousePointersByDisplay.find(destinationViewport.displayId) !=
Arpit Singhe33845c2024-10-25 20:59:24 +0000357 mMousePointersByDisplay.end()) {
358 LOG(FATAL) << "A cursor already exists on destination display"
Arpit Singhf0169ab2024-11-18 20:44:35 +0000359 << destinationViewport.displayId;
Arpit Singhe33845c2024-10-25 20:59:24 +0000360 }
Arpit Singhf0169ab2024-11-18 20:44:35 +0000361 mDefaultMouseDisplayId = destinationViewport.displayId;
Arpit Singhe33845c2024-10-25 20:59:24 +0000362 auto pcNode = mMousePointersByDisplay.extract(sourceDisplayId);
Arpit Singhf0169ab2024-11-18 20:44:35 +0000363 pcNode.key() = destinationViewport.displayId;
Arpit Singhe33845c2024-10-25 20:59:24 +0000364 mMousePointersByDisplay.insert(std::move(pcNode));
365
Arpit Singhf0169ab2024-11-18 20:44:35 +0000366 // Before updating the viewport and moving the cursor to appropriate location in the destination
367 // viewport, we need to temporarily hide the cursor. This will prevent it from appearing at the
368 // center of the display in any intermediate frames.
369 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
370 pc.setDisplayViewport(destinationViewport);
371 vec2 destinationPosition =
372 calculateDestinationPosition(destinationViewport, cursorOffset - destinationOffset,
373 sourceBoundary);
374
375 // Transform position back to un-rotated coordinate space before sending it to controller
376 destinationPosition = pc.getDisplayTransform().inverse().transform(destinationPosition.x,
377 destinationPosition.y);
378 pc.setPosition(destinationPosition.x, destinationPosition.y);
379 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
380}
381
382vec2 PointerChoreographer::calculateDestinationPosition(const DisplayViewport& destinationViewport,
383 float pointerOffset,
384 DisplayPosition sourceBoundary) {
385 // destination is opposite of the source boundary
386 switch (sourceBoundary) {
387 case DisplayPosition::RIGHT:
388 return {0, pointerOffset}; // left edge
389 case DisplayPosition::TOP:
390 return {pointerOffset, destinationViewport.logicalBottom}; // bottom edge
391 case DisplayPosition::LEFT:
392 return {destinationViewport.logicalRight, pointerOffset}; // right edge
393 case DisplayPosition::BOTTOM:
394 return {pointerOffset, 0}; // top edge
395 }
Arpit Singhe33845c2024-10-25 20:59:24 +0000396}
397
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000398void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700399 if (args.displayId == ui::LogicalDisplayId::INVALID) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000400 return;
401 }
402
403 if (args.getPointerCount() != 1) {
404 LOG(WARNING) << "Only drawing tablet events with a single pointer are currently supported: "
405 << args.dump();
406 }
407
408 // Use a mouse pointer controller for drawing tablets, or create one if it doesn't exist.
Arpit Singh420d0742024-04-04 11:54:20 +0000409 auto [it, controllerAdded] =
410 mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
411 getMouseControllerConstructor(
412 args.displayId));
413 if (controllerAdded) {
414 onControllerAddedOrRemovedLocked();
415 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000416
417 PointerControllerInterface& pc = *it->second;
418
419 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
420 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
421 pc.setPosition(x, y);
422 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
423 // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
424 // immediately by a DOWN event.
425 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
426 pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
427 } else if (canUnfadeOnDisplay(args.displayId)) {
428 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
429 }
430}
431
Byoungho Jungda10dd32023-10-06 17:03:45 +0900432/**
433 * When screen is touched, fade the mouse pointer on that display. We only call fade for
434 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
435 * mouse device keeps moving and unfades the cursor.
436 * For touch events, we do not need to populate the cursor position.
437 */
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900438void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800439 if (!args.displayId.isValid()) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900440 return;
441 }
442
Byoungho Jungda10dd32023-10-06 17:03:45 +0900443 if (const auto it = mMousePointersByDisplay.find(args.displayId);
444 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
445 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
446 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900447
448 if (!mShowTouchesEnabled) {
449 return;
450 }
451
452 // Get the touch pointer controller for the device, or create one if it doesn't exist.
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000453 auto [it, controllerAdded] =
454 mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
455 if (controllerAdded) {
Arpit Singh420d0742024-04-04 11:54:20 +0000456 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000457 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900458
459 PointerControllerInterface& pc = *it->second;
460
461 const PointerCoords* coords = args.pointerCoords.data();
462 const int32_t maskedAction = MotionEvent::getActionMasked(args.action);
463 const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
464 std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
465 BitSet32 idBits;
Linnan Li45b321e2024-07-17 19:33:21 +0000466 if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL &&
467 maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900468 for (size_t i = 0; i < args.getPointerCount(); i++) {
469 if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
470 continue;
471 }
472 uint32_t id = args.pointerProperties[i].id;
473 idToIndex[id] = i;
474 idBits.markBit(id);
475 }
476 }
477 // The PointerController already handles setting spots per-display, so
478 // we do not need to manually manage display changes for touch spots for now.
479 pc.setSpots(coords, idToIndex.cbegin(), idBits, args.displayId);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000480}
481
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900482void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& args) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800483 if (!args.displayId.isValid()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900484 return;
485 }
486
487 if (args.getPointerCount() != 1) {
488 LOG(WARNING) << "Only stylus hover events with a single pointer are currently supported: "
489 << args.dump();
490 }
491
492 // Get the stylus pointer controller for the device, or create one if it doesn't exist.
Arpit Singh420d0742024-04-04 11:54:20 +0000493 auto [it, controllerAdded] =
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900494 mStylusPointersByDevice.try_emplace(args.deviceId,
495 getStylusControllerConstructor(args.displayId));
Arpit Singh420d0742024-04-04 11:54:20 +0000496 if (controllerAdded) {
497 onControllerAddedOrRemovedLocked();
498 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900499
500 PointerControllerInterface& pc = *it->second;
501
502 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
503 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
504 pc.setPosition(x, y);
505 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000506 // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
507 // immediately by a DOWN event.
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900508 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhan888993d2024-09-17 20:01:48 +0000509 pc.updatePointerIcon(mShowTouchesEnabled ? PointerIconStyle::TYPE_SPOT_HOVER
510 : PointerIconStyle::TYPE_NOT_SPECIFIED);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000511 } else if (canUnfadeOnDisplay(args.displayId)) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900512 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
513 }
514}
515
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000516void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
517 mNextListener.notify(args);
518}
519
520void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
521 mNextListener.notify(args);
522}
523
524void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
525 mNextListener.notify(args);
526}
527
528void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900529 processDeviceReset(args);
530
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000531 mNextListener.notify(args);
532}
533
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900534void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) {
Arpit Singh7918c822024-11-20 11:28:44 +0000535 std::scoped_lock _l(getLock());
Prabir Pradhan16788792023-11-08 21:07:21 +0000536 mTouchPointersByDevice.erase(args.deviceId);
537 mStylusPointersByDevice.erase(args.deviceId);
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000538 mDrawingTabletPointersByDevice.erase(args.deviceId);
Arpit Singh420d0742024-04-04 11:54:20 +0000539 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000540}
541
Arpit Singh420d0742024-04-04 11:54:20 +0000542void PointerChoreographer::onControllerAddedOrRemovedLocked() {
Arpit Singhe33845c2024-10-25 20:59:24 +0000543 if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows() &&
544 !com::android::input::flags::connected_displays_cursor()) {
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000545 return;
546 }
Arpit Singh420d0742024-04-04 11:54:20 +0000547 bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() ||
548 !mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000549
Arpit Singh7918c822024-11-20 11:28:44 +0000550 // PointerChoreographer uses Listener's lock which is already held by caller
551 base::ScopedLockAssertion assumeLocked(mWindowInfoListener->mLock);
552
553 if (requireListener && !mIsWindowInfoListenerRegistered) {
554 mIsWindowInfoListenerRegistered = true;
555 mWindowInfoListener->setInitialDisplayInfosLocked(mRegisterListener(mWindowInfoListener));
556 onPrivacySensitiveDisplaysChangedLocked(
557 mWindowInfoListener->getPrivacySensitiveDisplaysLocked());
558 } else if (!requireListener && mIsWindowInfoListenerRegistered) {
559 mIsWindowInfoListenerRegistered = false;
Arpit Singhbd49b282024-05-23 18:02:54 +0000560 mUnregisterListener(mWindowInfoListener);
Arpit Singh7918c822024-11-20 11:28:44 +0000561 } else if (requireListener) {
Arpit Singh420d0742024-04-04 11:54:20 +0000562 // controller may have been added to an existing privacy sensitive display, we need to
563 // update all controllers again
Arpit Singh7918c822024-11-20 11:28:44 +0000564 onPrivacySensitiveDisplaysChangedLocked(
565 mWindowInfoListener->getPrivacySensitiveDisplaysLocked());
Arpit Singh420d0742024-04-04 11:54:20 +0000566 }
567}
568
569void PointerChoreographer::onPrivacySensitiveDisplaysChangedLocked(
570 const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) {
571 for (auto& [_, pc] : mTouchPointersByDevice) {
572 pc->clearSkipScreenshotFlags();
573 for (auto displayId : privacySensitiveDisplays) {
574 pc->setSkipScreenshotFlagForDisplay(displayId);
575 }
576 }
577
578 for (auto& [displayId, pc] : mMousePointersByDisplay) {
579 if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
580 pc->setSkipScreenshotFlagForDisplay(displayId);
581 } else {
582 pc->clearSkipScreenshotFlags();
583 }
584 }
585
586 for (auto* pointerControllerByDevice :
587 {&mDrawingTabletPointersByDevice, &mStylusPointersByDevice}) {
588 for (auto& [_, pc] : *pointerControllerByDevice) {
589 auto displayId = pc->getDisplayId();
590 if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
591 pc->setSkipScreenshotFlagForDisplay(displayId);
592 } else {
593 pc->clearSkipScreenshotFlags();
594 }
595 }
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000596 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900597}
598
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000599void PointerChoreographer::notifyPointerCaptureChanged(
600 const NotifyPointerCaptureChangedArgs& args) {
Hiroki Sato25040232024-02-22 17:21:22 +0900601 if (args.request.isEnable()) {
Arpit Singh7918c822024-11-20 11:28:44 +0000602 std::scoped_lock _l(getLock());
Byoungho Jungda10dd32023-10-06 17:03:45 +0900603 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
604 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
605 }
606 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000607 mNextListener.notify(args);
608}
609
Arpit Singhe33845c2024-10-25 20:59:24 +0000610void PointerChoreographer::setDisplayTopology(
611 const std::unordered_map<ui::LogicalDisplayId, std::vector<AdjacentDisplay>>&
612 displayTopology) {
613 std::scoped_lock _l(getLock());
614 mTopology = displayTopology;
615}
616
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000617void PointerChoreographer::dump(std::string& dump) {
Arpit Singh7918c822024-11-20 11:28:44 +0000618 std::scoped_lock _l(getLock());
Byoungho Jungda10dd32023-10-06 17:03:45 +0900619
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000620 dump += "PointerChoreographer:\n";
Harry Cuttsebd418a2024-08-16 15:52:24 +0000621 dump += StringPrintf(INDENT "Show Touches Enabled: %s\n",
622 mShowTouchesEnabled ? "true" : "false");
623 dump += StringPrintf(INDENT "Stylus PointerIcon Enabled: %s\n",
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900624 mStylusPointerIconEnabled ? "true" : "false");
Byoungho Jungda10dd32023-10-06 17:03:45 +0900625
626 dump += INDENT "MousePointerControllers:\n";
627 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
628 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
Linnan Li13bf76a2024-05-05 19:18:02 +0800629 dump += INDENT + displayId.toString() + " : " + pointerControllerDump;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900630 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900631 dump += INDENT "TouchPointerControllers:\n";
632 for (const auto& [deviceId, touchPointerController] : mTouchPointersByDevice) {
633 std::string pointerControllerDump = addLinePrefix(touchPointerController->dump(), INDENT);
634 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
635 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900636 dump += INDENT "StylusPointerControllers:\n";
637 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
638 std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
639 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
640 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000641 dump += INDENT "DrawingTabletControllers:\n";
642 for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
643 std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT);
644 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
645 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900646 dump += "\n";
647}
648
Linnan Li13bf76a2024-05-05 19:18:02 +0800649const DisplayViewport* PointerChoreographer::findViewportByIdLocked(
650 ui::LogicalDisplayId displayId) const {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900651 for (auto& viewport : mViewports) {
652 if (viewport.displayId == displayId) {
653 return &viewport;
654 }
655 }
656 return nullptr;
657}
658
Linnan Li13bf76a2024-05-05 19:18:02 +0800659ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked(
660 ui::LogicalDisplayId associatedDisplayId) const {
661 return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900662}
663
Linnan Li13bf76a2024-05-05 19:18:02 +0800664std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
665PointerChoreographer::ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) {
666 const ui::LogicalDisplayId displayId = getTargetMouseDisplayLocked(associatedDisplayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900667
Prabir Pradhan990d8712024-03-05 00:31:36 +0000668 auto it = mMousePointersByDisplay.find(displayId);
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000669 if (it == mMousePointersByDisplay.end()) {
670 it = mMousePointersByDisplay.emplace(displayId, getMouseControllerConstructor(displayId))
671 .first;
Arpit Singh420d0742024-04-04 11:54:20 +0000672 onControllerAddedOrRemovedLocked();
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000673 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900674
675 return {displayId, *it->second};
676}
677
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900678InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000679 auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
680 [deviceId](const auto& info) { return info.getId() == deviceId; });
681 return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900682}
683
Linnan Li13bf76a2024-05-05 19:18:02 +0800684bool PointerChoreographer::canUnfadeOnDisplay(ui::LogicalDisplayId displayId) {
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000685 return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
686}
687
Arpit Singh7918c822024-11-20 11:28:44 +0000688std::mutex& PointerChoreographer::getLock() const {
689 return mWindowInfoListener->mLock;
690}
691
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000692PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() {
Linnan Li13bf76a2024-05-05 19:18:02 +0800693 std::set<ui::LogicalDisplayId /*displayId*/> mouseDisplaysToKeep;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900694 std::set<DeviceId> touchDevicesToKeep;
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900695 std::set<DeviceId> stylusDevicesToKeep;
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000696 std::set<DeviceId> drawingTabletDevicesToKeep;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900697
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000698 // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
699 // new PointerControllers if necessary.
Byoungho Jungda10dd32023-10-06 17:03:45 +0900700 for (const auto& info : mInputDeviceInfos) {
Linnan Li48f80da2024-04-22 18:38:16 +0000701 if (!info.isEnabled()) {
702 // If device is disabled, we should not keep it, and should not show pointer for
703 // disabled mouse device.
704 continue;
705 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900706 const uint32_t sources = info.getSources();
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000707 const bool isKnownMouse = mMouseDevices.count(info.getId()) != 0;
708
709 if (isMouseOrTouchpad(sources) || isKnownMouse) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800710 const ui::LogicalDisplayId displayId =
711 getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000712 mouseDisplaysToKeep.insert(displayId);
713 // For mice, show the cursor immediately when the device is first connected or
714 // when it moves to a new display.
715 auto [mousePointerIt, isNewMousePointer] =
716 mMousePointersByDisplay.try_emplace(displayId,
717 getMouseControllerConstructor(displayId));
Arpit Singh420d0742024-04-04 11:54:20 +0000718 if (isNewMousePointer) {
719 onControllerAddedOrRemovedLocked();
720 }
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000721
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000722 mMouseDevices.emplace(info.getId());
723 if ((!isKnownMouse || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000724 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
725 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900726 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900727 if (isFromSource(sources, AINPUT_SOURCE_TOUCHSCREEN) && mShowTouchesEnabled &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800728 info.getAssociatedDisplayId().isValid()) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900729 touchDevicesToKeep.insert(info.getId());
730 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900731 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && mStylusPointerIconEnabled &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800732 info.getAssociatedDisplayId().isValid()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900733 stylusDevicesToKeep.insert(info.getId());
734 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000735 if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE) &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800736 info.getAssociatedDisplayId().isValid()) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000737 drawingTabletDevicesToKeep.insert(info.getId());
738 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900739 }
740
741 // Remove PointerControllers no longer needed.
Prabir Pradhan19767602023-11-03 16:53:31 +0000742 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000743 return mouseDisplaysToKeep.find(pair.first) == mouseDisplaysToKeep.end();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900744 });
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900745 std::erase_if(mTouchPointersByDevice, [&touchDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000746 return touchDevicesToKeep.find(pair.first) == touchDevicesToKeep.end();
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900747 });
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900748 std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000749 return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900750 });
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000751 std::erase_if(mDrawingTabletPointersByDevice, [&drawingTabletDevicesToKeep](const auto& pair) {
752 return drawingTabletDevicesToKeep.find(pair.first) == drawingTabletDevicesToKeep.end();
753 });
Arpit Singh7918c822024-11-20 11:28:44 +0000754 std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(getLock()) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000755 return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
756 [id](const auto& info) { return info.getId() == id; }) ==
757 mInputDeviceInfos.end();
758 });
Byoungho Jungda10dd32023-10-06 17:03:45 +0900759
Arpit Singh420d0742024-04-04 11:54:20 +0000760 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000761
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000762 // Check if we need to notify the policy if there's a change on the pointer display ID.
763 return calculatePointerDisplayChangeToNotify();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900764}
765
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000766PointerChoreographer::PointerDisplayChange
767PointerChoreographer::calculatePointerDisplayChangeToNotify() {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700768 ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
Arpit Singh7f21fa32024-11-26 15:44:26 +0000769 vec2 cursorPosition = {0, 0};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900770 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
771 it != mMousePointersByDisplay.end()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000772 const auto& pointerController = it->second;
773 // Use the displayId from the pointerController, because it accurately reflects whether
774 // the viewport has been added for that display. Otherwise, we would have to check if
775 // the viewport exists separately.
776 displayIdToNotify = pointerController->getDisplayId();
777 cursorPosition = pointerController->getPosition();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900778 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900779 if (mNotifiedPointerDisplayId == displayIdToNotify) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000780 return {};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900781 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900782 mNotifiedPointerDisplayId = displayIdToNotify;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000783 return {{displayIdToNotify, cursorPosition}};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900784}
785
Linnan Li13bf76a2024-05-05 19:18:02 +0800786void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000787 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900788
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000789 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000790 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000791
792 mDefaultMouseDisplayId = displayId;
793 pointerDisplayChange = updatePointerControllersLocked();
794 } // release lock
795
796 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900797}
798
799void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000800 PointerDisplayChange pointerDisplayChange;
801
802 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000803 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000804 for (const auto& viewport : viewports) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800805 const ui::LogicalDisplayId displayId = viewport.displayId;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000806 if (const auto it = mMousePointersByDisplay.find(displayId);
807 it != mMousePointersByDisplay.end()) {
808 it->second->setDisplayViewport(viewport);
809 }
810 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
811 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
812 if (info && info->getAssociatedDisplayId() == displayId) {
813 stylusPointerController->setDisplayViewport(viewport);
814 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900815 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000816 for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
817 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
818 if (info && info->getAssociatedDisplayId() == displayId) {
819 drawingTabletController->setDisplayViewport(viewport);
820 }
821 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900822 }
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000823 mViewports = viewports;
824 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
825 } // release lock
826
827 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900828}
829
830std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
Linnan Li13bf76a2024-05-05 19:18:02 +0800831 ui::LogicalDisplayId associatedDisplayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000832 std::scoped_lock _l(getLock());
Linnan Li13bf76a2024-05-05 19:18:02 +0800833 const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900834 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
835 return *viewport;
836 }
837 return std::nullopt;
838}
839
Arpit Singh7f21fa32024-11-26 15:44:26 +0000840vec2 PointerChoreographer::getMouseCursorPosition(ui::LogicalDisplayId displayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000841 std::scoped_lock _l(getLock());
Linnan Li13bf76a2024-05-05 19:18:02 +0800842 const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900843 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
844 it != mMousePointersByDisplay.end()) {
845 return it->second->getPosition();
846 }
847 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000848}
849
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900850void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000851 PointerDisplayChange pointerDisplayChange;
852
853 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000854 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000855 if (mShowTouchesEnabled == enabled) {
856 return;
857 }
858 mShowTouchesEnabled = enabled;
859 pointerDisplayChange = updatePointerControllersLocked();
860 } // release lock
861
862 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900863}
864
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900865void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000866 PointerDisplayChange pointerDisplayChange;
867
868 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000869 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000870 if (mStylusPointerIconEnabled == enabled) {
871 return;
872 }
873 mStylusPointerIconEnabled = enabled;
874 pointerDisplayChange = updatePointerControllersLocked();
875 } // release lock
876
877 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900878}
879
Byoungho Jung99326452023-11-03 20:19:17 +0900880bool PointerChoreographer::setPointerIcon(
Linnan Li13bf76a2024-05-05 19:18:02 +0800881 std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
882 ui::LogicalDisplayId displayId, DeviceId deviceId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000883 std::scoped_lock _l(getLock());
Byoungho Jung99326452023-11-03 20:19:17 +0900884 if (deviceId < 0) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000885 LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900886 return false;
887 }
888 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
889 if (!info) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000890 LOG(WARNING) << "No input device info found for id " << deviceId
891 << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900892 return false;
893 }
894 const uint32_t sources = info->getSources();
Byoungho Jung99326452023-11-03 20:19:17 +0900895
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000896 if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE)) {
897 auto it = mDrawingTabletPointersByDevice.find(deviceId);
898 if (it != mDrawingTabletPointersByDevice.end()) {
899 setIconForController(icon, *it->second);
900 return true;
Byoungho Jung99326452023-11-03 20:19:17 +0900901 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000902 }
903 if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) {
904 auto it = mStylusPointersByDevice.find(deviceId);
905 if (it != mStylusPointersByDevice.end()) {
Prabir Pradhan888993d2024-09-17 20:01:48 +0000906 if (mShowTouchesEnabled) {
907 // If an app doesn't override the icon for the hovering stylus, show the hover icon.
908 auto* style = std::get_if<PointerIconStyle>(&icon);
909 if (style != nullptr && *style == PointerIconStyle::TYPE_NOT_SPECIFIED) {
910 *style = PointerIconStyle::TYPE_SPOT_HOVER;
911 }
912 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000913 setIconForController(icon, *it->second);
914 return true;
915 }
916 }
917 if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
918 auto it = mMousePointersByDisplay.find(displayId);
919 if (it != mMousePointersByDisplay.end()) {
920 setIconForController(icon, *it->second);
921 return true;
Byoungho Jung99326452023-11-03 20:19:17 +0900922 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000923 LOG(WARNING) << "No mouse pointer controller found for display " << displayId
924 << ", device " << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900925 return false;
926 }
Byoungho Jung99326452023-11-03 20:19:17 +0900927 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000928 LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device " << deviceId
929 << ".";
930 return false;
Byoungho Jung99326452023-11-03 20:19:17 +0900931}
932
Linnan Li13bf76a2024-05-05 19:18:02 +0800933void PointerChoreographer::setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) {
Arpit Singh7918c822024-11-20 11:28:44 +0000934 std::scoped_lock lock(getLock());
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000935 if (visible) {
936 mDisplaysWithPointersHidden.erase(displayId);
937 // We do not unfade the icons here, because we don't know when the last event happened.
938 return;
939 }
940
941 mDisplaysWithPointersHidden.emplace(displayId);
942
943 // Hide any icons that are currently visible on the display.
944 if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
945 const auto& [_, controller] = *it;
946 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
947 }
948 for (const auto& [_, controller] : mStylusPointersByDevice) {
949 if (controller->getDisplayId() == displayId) {
950 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
951 }
952 }
953}
954
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000955void PointerChoreographer::setFocusedDisplay(ui::LogicalDisplayId displayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000956 std::scoped_lock lock(getLock());
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000957 mCurrentFocusedDisplay = displayId;
958}
959
Prabir Pradhan19767602023-11-03 16:53:31 +0000960PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
Linnan Li13bf76a2024-05-05 19:18:02 +0800961 ui::LogicalDisplayId displayId) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000962 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
Arpit Singh7918c822024-11-20 11:28:44 +0000963 [this, displayId]() REQUIRES(getLock()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000964 auto pc = mPolicy.createPointerController(
965 PointerControllerInterface::ControllerType::MOUSE);
966 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
967 pc->setDisplayViewport(*viewport);
968 }
969 return pc;
970 };
971 return ConstructorDelegate(std::move(ctor));
972}
973
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900974PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor(
Linnan Li13bf76a2024-05-05 19:18:02 +0800975 ui::LogicalDisplayId displayId) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900976 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
Arpit Singh7918c822024-11-20 11:28:44 +0000977 [this, displayId]() REQUIRES(getLock()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900978 auto pc = mPolicy.createPointerController(
979 PointerControllerInterface::ControllerType::STYLUS);
980 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
981 pc->setDisplayViewport(*viewport);
982 }
983 return pc;
984 };
985 return ConstructorDelegate(std::move(ctor));
986}
987
Arpit Singhe33845c2024-10-25 20:59:24 +0000988void PointerChoreographer::populateFakeDisplayTopologyLocked(
989 const std::vector<gui::DisplayInfo>& displayInfos) {
990 if (!com::android::input::flags::connected_displays_cursor()) {
991 return;
992 }
993
994 if (displayInfos.size() == mTopology.size()) {
995 bool displaysChanged = false;
996 for (const auto& displayInfo : displayInfos) {
997 if (mTopology.find(displayInfo.displayId) == mTopology.end()) {
998 displaysChanged = true;
999 break;
1000 }
1001 }
1002
1003 if (!displaysChanged) {
1004 return;
1005 }
1006 }
1007
1008 // create a fake topology assuming following order
1009 // default-display (top-edge) -> next-display (right-edge) -> next-display (right-edge) ...
Arpit Singhf0169ab2024-11-18 20:44:35 +00001010 // This also adds a 100px offset on corresponding edge for better manual testing
1011 // ┌────────┐
1012 // │ next ├─────────┐
1013 // ┌─└───────┐┤ next 2 │ ...
1014 // │ default │└─────────┘
Arpit Singhe33845c2024-10-25 20:59:24 +00001015 // └─────────┘
1016 mTopology.clear();
1017
1018 // treat default display as base, in real topology it should be the primary-display
1019 ui::LogicalDisplayId previousDisplay = ui::LogicalDisplayId::DEFAULT;
1020 for (const auto& displayInfo : displayInfos) {
1021 if (displayInfo.displayId == ui::LogicalDisplayId::DEFAULT) {
1022 continue;
1023 }
1024 if (previousDisplay == ui::LogicalDisplayId::DEFAULT) {
Arpit Singhf0169ab2024-11-18 20:44:35 +00001025 mTopology[previousDisplay].push_back(
1026 {displayInfo.displayId, DisplayPosition::TOP, 100});
Arpit Singhe33845c2024-10-25 20:59:24 +00001027 mTopology[displayInfo.displayId].push_back(
Arpit Singhf0169ab2024-11-18 20:44:35 +00001028 {previousDisplay, DisplayPosition::BOTTOM, -100});
Arpit Singhe33845c2024-10-25 20:59:24 +00001029 } else {
1030 mTopology[previousDisplay].push_back(
Arpit Singhf0169ab2024-11-18 20:44:35 +00001031 {displayInfo.displayId, DisplayPosition::RIGHT, 100});
1032 mTopology[displayInfo.displayId].push_back(
1033 {previousDisplay, DisplayPosition::LEFT, -100});
Arpit Singhe33845c2024-10-25 20:59:24 +00001034 }
1035 previousDisplay = displayInfo.displayId;
1036 }
1037
1038 // update default pointer display. In real topology it should be the primary-display
1039 if (mTopology.find(mDefaultMouseDisplayId) == mTopology.end()) {
1040 mDefaultMouseDisplayId = ui::LogicalDisplayId::DEFAULT;
1041 }
1042}
1043
Arpit Singhf0169ab2024-11-18 20:44:35 +00001044std::optional<std::pair<const DisplayViewport*, float /*offset*/>>
1045PointerChoreographer::findDestinationDisplayLocked(const ui::LogicalDisplayId sourceDisplayId,
1046 const DisplayPosition sourceBoundary,
1047 float cursorOffset) const {
1048 const auto& sourceNode = mTopology.find(sourceDisplayId);
1049 if (sourceNode == mTopology.end()) {
Arpit Singhe33845c2024-10-25 20:59:24 +00001050 // Topology is likely out of sync with viewport info, wait for it to be updated
Arpit Singhf0169ab2024-11-18 20:44:35 +00001051 LOG(WARNING) << "Source display missing from topology " << sourceDisplayId;
Arpit Singhe33845c2024-10-25 20:59:24 +00001052 return std::nullopt;
1053 }
Arpit Singhf0169ab2024-11-18 20:44:35 +00001054 for (const AdjacentDisplay& adjacentDisplay : sourceNode->second) {
Arpit Singhe33845c2024-10-25 20:59:24 +00001055 if (adjacentDisplay.position != sourceBoundary) {
1056 continue;
1057 }
1058 const DisplayViewport* destinationViewport =
1059 findViewportByIdLocked(adjacentDisplay.displayId);
1060 if (destinationViewport == nullptr) {
1061 // Topology is likely out of sync with viewport info, wait for them to be updated
1062 LOG(WARNING) << "Cannot find viewport for adjacent display "
Arpit Singhf0169ab2024-11-18 20:44:35 +00001063 << adjacentDisplay.displayId << "of source display " << sourceDisplayId;
1064 continue;
Arpit Singhe33845c2024-10-25 20:59:24 +00001065 }
Arpit Singhf0169ab2024-11-18 20:44:35 +00001066 // target position must be within target display boundary
1067 const int32_t edgeSize =
1068 sourceBoundary == DisplayPosition::TOP || sourceBoundary == DisplayPosition::BOTTOM
1069 ? (destinationViewport->logicalRight - destinationViewport->logicalLeft)
1070 : (destinationViewport->logicalBottom - destinationViewport->logicalTop);
1071 if (cursorOffset >= adjacentDisplay.offsetPx &&
1072 cursorOffset <= adjacentDisplay.offsetPx + edgeSize) {
1073 return std::make_pair(destinationViewport, adjacentDisplay.offsetPx);
1074 }
Arpit Singhe33845c2024-10-25 20:59:24 +00001075 }
1076 return std::nullopt;
1077}
1078
Arpit Singh7918c822024-11-20 11:28:44 +00001079// --- PointerChoreographer::PointerChoreographerDisplayInfoListener ---
1080
Arpit Singh4b6ad2d2024-04-04 11:54:20 +00001081void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfosChanged(
1082 const gui::WindowInfosUpdate& windowInfosUpdate) {
Arpit Singh7918c822024-11-20 11:28:44 +00001083 std::scoped_lock _l(mLock);
Arpit Singh420d0742024-04-04 11:54:20 +00001084 if (mPointerChoreographer == nullptr) {
1085 return;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +00001086 }
Arpit Singh420d0742024-04-04 11:54:20 +00001087 auto newPrivacySensitiveDisplays =
1088 getPrivacySensitiveDisplaysFromWindowInfos(windowInfosUpdate.windowInfos);
Arpit Singhe33845c2024-10-25 20:59:24 +00001089
1090 // PointerChoreographer uses Listener's lock.
1091 base::ScopedLockAssertion assumeLocked(mPointerChoreographer->getLock());
Arpit Singh420d0742024-04-04 11:54:20 +00001092 if (newPrivacySensitiveDisplays != mPrivacySensitiveDisplays) {
1093 mPrivacySensitiveDisplays = std::move(newPrivacySensitiveDisplays);
Arpit Singh7918c822024-11-20 11:28:44 +00001094 mPointerChoreographer->onPrivacySensitiveDisplaysChangedLocked(mPrivacySensitiveDisplays);
Arpit Singh420d0742024-04-04 11:54:20 +00001095 }
Arpit Singhe33845c2024-10-25 20:59:24 +00001096 mPointerChoreographer->populateFakeDisplayTopologyLocked(windowInfosUpdate.displayInfos);
Arpit Singh420d0742024-04-04 11:54:20 +00001097}
1098
Arpit Singh7918c822024-11-20 11:28:44 +00001099void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfosLocked(
Arpit Singh420d0742024-04-04 11:54:20 +00001100 const std::vector<gui::WindowInfo>& windowInfos) {
Arpit Singh420d0742024-04-04 11:54:20 +00001101 mPrivacySensitiveDisplays = getPrivacySensitiveDisplaysFromWindowInfos(windowInfos);
1102}
1103
1104std::unordered_set<ui::LogicalDisplayId /*displayId*/>
Arpit Singh7918c822024-11-20 11:28:44 +00001105PointerChoreographer::PointerChoreographerDisplayInfoListener::getPrivacySensitiveDisplaysLocked() {
Arpit Singh420d0742024-04-04 11:54:20 +00001106 return mPrivacySensitiveDisplays;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +00001107}
1108
1109void PointerChoreographer::PointerChoreographerDisplayInfoListener::
1110 onPointerChoreographerDestroyed() {
Arpit Singh7918c822024-11-20 11:28:44 +00001111 std::scoped_lock _l(mLock);
Arpit Singh4b6ad2d2024-04-04 11:54:20 +00001112 mPointerChoreographer = nullptr;
1113}
1114
Prabir Pradhanb56e92c2023-06-09 23:40:37 +00001115} // namespace android