blob: 8eb6bdd02f8e307e7e27cab246dd143c21e1c9e8 [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
Linnan Li13bf76a2024-05-05 19:18:02 +080067inline void notifyPointerDisplayChange(
68 std::optional<std::tuple<ui::LogicalDisplayId, FloatPoint>> change,
69 PointerChoreographerPolicyInterface& policy) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +000070 if (!change) {
71 return;
72 }
73 const auto& [displayId, cursorPosition] = *change;
74 policy.notifyPointerDisplayIdChanged(displayId, cursorPosition);
75}
76
Prabir Pradhan4c977a42024-03-15 16:47:37 +000077void setIconForController(const std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle>& icon,
78 PointerControllerInterface& controller) {
79 if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
80 if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
81 LOG(FATAL) << "SpriteIcon should not be null";
82 }
83 controller.setCustomPointerIcon(*std::get<std::unique_ptr<SpriteIcon>>(icon));
84 } else {
85 controller.updatePointerIcon(std::get<PointerIconStyle>(icon));
86 }
87}
88
Arpit Singh420d0742024-04-04 11:54:20 +000089// filters and returns a set of privacy sensitive displays that are currently visible.
90std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysFromWindowInfos(
91 const std::vector<gui::WindowInfo>& windowInfos) {
92 std::unordered_set<ui::LogicalDisplayId> privacySensitiveDisplays;
93 for (const auto& windowInfo : windowInfos) {
94 if (!windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE) &&
95 windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY)) {
96 privacySensitiveDisplays.insert(windowInfo.displayId);
97 }
98 }
99 return privacySensitiveDisplays;
100}
101
Byoungho Jungda10dd32023-10-06 17:03:45 +0900102} // namespace
103
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000104// --- PointerChoreographer ---
105
Arpit Singhbd49b282024-05-23 18:02:54 +0000106PointerChoreographer::PointerChoreographer(InputListenerInterface& inputListener,
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000107 PointerChoreographerPolicyInterface& policy)
Arpit Singhbd49b282024-05-23 18:02:54 +0000108 : PointerChoreographer(
109 inputListener, policy,
110 [](const sp<android::gui::WindowInfosListener>& listener) {
111 auto initialInfo = std::make_pair(std::vector<android::gui::WindowInfo>{},
112 std::vector<android::gui::DisplayInfo>{});
113#if defined(__ANDROID__)
114 SurfaceComposerClient::getDefault()->addWindowInfosListener(listener,
115 &initialInfo);
116#endif
117 return initialInfo.first;
118 },
119 [](const sp<android::gui::WindowInfosListener>& listener) {
120#if defined(__ANDROID__)
121 SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
122#endif
123 }) {
124}
125
126PointerChoreographer::PointerChoreographer(
127 android::InputListenerInterface& listener,
128 android::PointerChoreographerPolicyInterface& policy,
129 const android::PointerChoreographer::WindowListenerRegisterConsumer& registerListener,
130 const android::PointerChoreographer::WindowListenerUnregisterConsumer& unregisterListener)
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000131 : mTouchControllerConstructor([this]() {
Prabir Pradhan16788792023-11-08 21:07:21 +0000132 return mPolicy.createPointerController(
133 PointerControllerInterface::ControllerType::TOUCH);
134 }),
135 mNextListener(listener),
Byoungho Jungda10dd32023-10-06 17:03:45 +0900136 mPolicy(policy),
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700137 mDefaultMouseDisplayId(ui::LogicalDisplayId::DEFAULT),
138 mNotifiedPointerDisplayId(ui::LogicalDisplayId::INVALID),
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900139 mShowTouchesEnabled(false),
Arpit Singhbd49b282024-05-23 18:02:54 +0000140 mStylusPointerIconEnabled(false),
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000141 mCurrentFocusedDisplay(ui::LogicalDisplayId::DEFAULT),
Arpit Singh7918c822024-11-20 11:28:44 +0000142 mIsWindowInfoListenerRegistered(false),
143 mWindowInfoListener(sp<PointerChoreographerDisplayInfoListener>::make(this)),
Arpit Singhbd49b282024-05-23 18:02:54 +0000144 mRegisterListener(registerListener),
145 mUnregisterListener(unregisterListener) {}
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000146
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000147PointerChoreographer::~PointerChoreographer() {
Arpit Singh7918c822024-11-20 11:28:44 +0000148 if (mIsWindowInfoListenerRegistered) {
149 mUnregisterListener(mWindowInfoListener);
150 mIsWindowInfoListenerRegistered = false;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000151 }
152 mWindowInfoListener->onPointerChoreographerDestroyed();
153}
154
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000155void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000156 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900157
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000158 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000159 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000160
161 mInputDeviceInfos = args.inputDeviceInfos;
162 pointerDisplayChange = updatePointerControllersLocked();
163 } // release lock
164
165 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000166 mNextListener.notify(args);
167}
168
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000169void PointerChoreographer::notifyKey(const NotifyKeyArgs& args) {
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000170 fadeMouseCursorOnKeyPress(args);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000171 mNextListener.notify(args);
172}
173
174void PointerChoreographer::notifyMotion(const NotifyMotionArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900175 NotifyMotionArgs newArgs = processMotion(args);
176
177 mNextListener.notify(newArgs);
178}
179
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000180void PointerChoreographer::fadeMouseCursorOnKeyPress(const android::NotifyKeyArgs& args) {
181 if (args.action == AKEY_EVENT_ACTION_UP || isMetaKey(args.keyCode)) {
182 return;
183 }
184 // Meta state for these keys is ignored for dismissing cursor while typing
185 constexpr static int32_t ALLOW_FADING_META_STATE_MASK = AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON |
186 AMETA_SCROLL_LOCK_ON | AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON | AMETA_SHIFT_ON;
187 if (args.metaState & ~ALLOW_FADING_META_STATE_MASK) {
188 // Do not fade if any other meta state is active
189 return;
190 }
191 if (!mPolicy.isInputMethodConnectionActive()) {
192 return;
193 }
194
Arpit Singh7918c822024-11-20 11:28:44 +0000195 std::scoped_lock _l(getLock());
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000196 ui::LogicalDisplayId targetDisplay = args.displayId;
197 if (targetDisplay == ui::LogicalDisplayId::INVALID) {
198 targetDisplay = mCurrentFocusedDisplay;
199 }
200 auto it = mMousePointersByDisplay.find(targetDisplay);
201 if (it != mMousePointersByDisplay.end()) {
Arpit Singh849beb42024-06-06 07:14:17 +0000202 mPolicy.notifyMouseCursorFadedOnTyping();
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000203 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
204 }
205}
206
Byoungho Jungda10dd32023-10-06 17:03:45 +0900207NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& args) {
Arpit Singhe33845c2024-10-25 20:59:24 +0000208 NotifyMotionArgs newArgs(args);
209 PointerDisplayChange pointerDisplayChange;
210 { // acquire lock
211 std::scoped_lock _l(getLock());
212 if (isFromMouse(args)) {
213 newArgs = processMouseEventLocked(args);
214 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
215 } else if (isFromTouchpad(args)) {
216 newArgs = processTouchpadEventLocked(args);
217 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
218 } else if (isFromDrawingTablet(args)) {
219 processDrawingTabletEventLocked(args);
220 } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
221 processStylusHoverEventLocked(args);
222 } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
223 processTouchscreenAndStylusEventLocked(args);
224 }
225 } // release lock
Byoungho Jungda10dd32023-10-06 17:03:45 +0900226
Arpit Singhe33845c2024-10-25 20:59:24 +0000227 if (pointerDisplayChange) {
228 // pointer display may have changed if mouse crossed display boundary
229 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900230 }
Arpit Singhe33845c2024-10-25 20:59:24 +0000231 return newArgs;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900232}
233
234NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotionArgs& args) {
235 if (args.getPointerCount() != 1) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000236 LOG(FATAL) << "Only mouse events with a single pointer are currently supported: "
237 << args.dump();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900238 }
239
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000240 mMouseDevices.emplace(args.deviceId);
Prabir Pradhan990d8712024-03-05 00:31:36 +0000241 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900242 NotifyMotionArgs newArgs(args);
243 newArgs.displayId = displayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900244
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900245 if (MotionEvent::isValidCursorPosition(args.xCursorPosition, args.yCursorPosition)) {
246 // This is an absolute mouse device that knows about the location of the cursor on the
247 // display, so set the cursor position to the specified location.
248 const auto [x, y] = pc.getPosition();
249 const float deltaX = args.xCursorPosition - x;
250 const float deltaY = args.yCursorPosition - y;
251 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
252 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
253 pc.setPosition(args.xCursorPosition, args.yCursorPosition);
254 } else {
255 // This is a relative mouse, so move the cursor by the specified amount.
Arpit Singh5cd74972024-11-25 11:17:42 +0000256 processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc);
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900257 }
Arpit Singhe33845c2024-10-25 20:59:24 +0000258 // Note displayId may have changed if the cursor moved to a different display
259 if (canUnfadeOnDisplay(newArgs.displayId)) {
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000260 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
261 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900262 return newArgs;
263}
264
Byoungho Jungee6268f2023-10-30 17:27:26 +0900265NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000266 mMouseDevices.emplace(args.deviceId);
Prabir Pradhan990d8712024-03-05 00:31:36 +0000267 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900268
269 NotifyMotionArgs newArgs(args);
270 newArgs.displayId = displayId;
271 if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
272 // This is a movement of the mouse pointer.
Arpit Singh5cd74972024-11-25 11:17:42 +0000273 processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900274 } else {
275 // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
Byoungho Jungee6268f2023-10-30 17:27:26 +0900276 const auto [x, y] = pc.getPosition();
277 for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
278 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
279 args.pointerCoords[i].getX() + x);
280 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
281 args.pointerCoords[i].getY() + y);
282 }
283 newArgs.xCursorPosition = x;
284 newArgs.yCursorPosition = y;
285 }
Arpit Singhe33845c2024-10-25 20:59:24 +0000286
287 // Note displayId may have changed if the cursor moved to a different display
288 if (canUnfadeOnDisplay(newArgs.displayId)) {
Arpit Singh5cd74972024-11-25 11:17:42 +0000289 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
290 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900291 return newArgs;
292}
293
Arpit Singh5cd74972024-11-25 11:17:42 +0000294void PointerChoreographer::processPointerDeviceMotionEventLocked(NotifyMotionArgs& newArgs,
295 PointerControllerInterface& pc) {
296 const float deltaX = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
297 const float deltaY = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
298
Arpit Singhe33845c2024-10-25 20:59:24 +0000299 FloatPoint unconsumedDelta = pc.move(deltaX, deltaY);
300 if (com::android::input::flags::connected_displays_cursor() &&
301 (std::abs(unconsumedDelta.x) > 0 || std::abs(unconsumedDelta.y) > 0)) {
302 handleUnconsumedDeltaLocked(pc, unconsumedDelta);
303 // pointer may have moved to a different viewport
304 newArgs.displayId = pc.getDisplayId();
305 }
306
Arpit Singh5cd74972024-11-25 11:17:42 +0000307 const auto [x, y] = pc.getPosition();
308 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
309 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
310 newArgs.xCursorPosition = x;
311 newArgs.yCursorPosition = y;
312}
313
Arpit Singhe33845c2024-10-25 20:59:24 +0000314void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterface& pc,
315 const FloatPoint& unconsumedDelta) {
Arpit Singhf0169ab2024-11-18 20:44:35 +0000316 // Display topology is in rotated coordinate space and Pointer controller returns and expects
317 // values in the un-rotated coordinate space. So we need to transform delta and cursor position
318 // back to the rotated coordinate space to lookup adjacent display in the display topology.
319 const auto& sourceDisplayTransform = pc.getDisplayTransform();
320 const vec2 rotatedUnconsumedDelta =
321 transformWithoutTranslation(sourceDisplayTransform,
322 {unconsumedDelta.x, unconsumedDelta.y});
323 const FloatPoint cursorPosition = pc.getPosition();
324 const vec2 rotatedCursorPosition =
325 sourceDisplayTransform.transform(cursorPosition.x, cursorPosition.y);
326
327 // To find out the boundary that cursor is crossing we are checking delta in x and y direction
328 // respectively. This prioritizes x direction over y.
329 // In practise, majority of cases we only have non-zero values in either x or y coordinates,
330 // except sometimes near the corners.
331 // In these cases this behaviour is not noticeable. We also do not apply unconsumed delta on
332 // the destination display for the same reason.
333 DisplayPosition sourceBoundary;
334 float cursorOffset = 0.0f;
335 if (rotatedUnconsumedDelta.x > 0) {
336 sourceBoundary = DisplayPosition::RIGHT;
337 cursorOffset = rotatedCursorPosition.y;
338 } else if (rotatedUnconsumedDelta.x < 0) {
339 sourceBoundary = DisplayPosition::LEFT;
340 cursorOffset = rotatedCursorPosition.y;
341 } else if (rotatedUnconsumedDelta.y > 0) {
342 sourceBoundary = DisplayPosition::BOTTOM;
343 cursorOffset = rotatedCursorPosition.x;
344 } else {
345 sourceBoundary = DisplayPosition::TOP;
346 cursorOffset = rotatedCursorPosition.x;
347 }
348
Arpit Singhe33845c2024-10-25 20:59:24 +0000349 const ui::LogicalDisplayId sourceDisplayId = pc.getDisplayId();
Arpit Singhf0169ab2024-11-18 20:44:35 +0000350 std::optional<std::pair<const DisplayViewport*, float /*offset*/>> destination =
351 findDestinationDisplayLocked(sourceDisplayId, sourceBoundary, cursorOffset);
352 if (!destination.has_value()) {
353 // No matching adjacent display
Arpit Singhe33845c2024-10-25 20:59:24 +0000354 return;
355 }
356
Arpit Singhf0169ab2024-11-18 20:44:35 +0000357 const DisplayViewport& destinationViewport = *destination->first;
358 const float destinationOffset = destination->second;
359 if (mMousePointersByDisplay.find(destinationViewport.displayId) !=
Arpit Singhe33845c2024-10-25 20:59:24 +0000360 mMousePointersByDisplay.end()) {
361 LOG(FATAL) << "A cursor already exists on destination display"
Arpit Singhf0169ab2024-11-18 20:44:35 +0000362 << destinationViewport.displayId;
Arpit Singhe33845c2024-10-25 20:59:24 +0000363 }
Arpit Singhf0169ab2024-11-18 20:44:35 +0000364 mDefaultMouseDisplayId = destinationViewport.displayId;
Arpit Singhe33845c2024-10-25 20:59:24 +0000365 auto pcNode = mMousePointersByDisplay.extract(sourceDisplayId);
Arpit Singhf0169ab2024-11-18 20:44:35 +0000366 pcNode.key() = destinationViewport.displayId;
Arpit Singhe33845c2024-10-25 20:59:24 +0000367 mMousePointersByDisplay.insert(std::move(pcNode));
368
Arpit Singhf0169ab2024-11-18 20:44:35 +0000369 // Before updating the viewport and moving the cursor to appropriate location in the destination
370 // viewport, we need to temporarily hide the cursor. This will prevent it from appearing at the
371 // center of the display in any intermediate frames.
372 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
373 pc.setDisplayViewport(destinationViewport);
374 vec2 destinationPosition =
375 calculateDestinationPosition(destinationViewport, cursorOffset - destinationOffset,
376 sourceBoundary);
377
378 // Transform position back to un-rotated coordinate space before sending it to controller
379 destinationPosition = pc.getDisplayTransform().inverse().transform(destinationPosition.x,
380 destinationPosition.y);
381 pc.setPosition(destinationPosition.x, destinationPosition.y);
382 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
383}
384
385vec2 PointerChoreographer::calculateDestinationPosition(const DisplayViewport& destinationViewport,
386 float pointerOffset,
387 DisplayPosition sourceBoundary) {
388 // destination is opposite of the source boundary
389 switch (sourceBoundary) {
390 case DisplayPosition::RIGHT:
391 return {0, pointerOffset}; // left edge
392 case DisplayPosition::TOP:
393 return {pointerOffset, destinationViewport.logicalBottom}; // bottom edge
394 case DisplayPosition::LEFT:
395 return {destinationViewport.logicalRight, pointerOffset}; // right edge
396 case DisplayPosition::BOTTOM:
397 return {pointerOffset, 0}; // top edge
398 }
Arpit Singhe33845c2024-10-25 20:59:24 +0000399}
400
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000401void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700402 if (args.displayId == ui::LogicalDisplayId::INVALID) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000403 return;
404 }
405
406 if (args.getPointerCount() != 1) {
407 LOG(WARNING) << "Only drawing tablet events with a single pointer are currently supported: "
408 << args.dump();
409 }
410
411 // Use a mouse pointer controller for drawing tablets, or create one if it doesn't exist.
Arpit Singh420d0742024-04-04 11:54:20 +0000412 auto [it, controllerAdded] =
413 mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
414 getMouseControllerConstructor(
415 args.displayId));
416 if (controllerAdded) {
417 onControllerAddedOrRemovedLocked();
418 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000419
420 PointerControllerInterface& pc = *it->second;
421
422 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
423 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
424 pc.setPosition(x, y);
425 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
426 // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
427 // immediately by a DOWN event.
428 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
429 pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
430 } else if (canUnfadeOnDisplay(args.displayId)) {
431 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
432 }
433}
434
Byoungho Jungda10dd32023-10-06 17:03:45 +0900435/**
436 * When screen is touched, fade the mouse pointer on that display. We only call fade for
437 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
438 * mouse device keeps moving and unfades the cursor.
439 * For touch events, we do not need to populate the cursor position.
440 */
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900441void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800442 if (!args.displayId.isValid()) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900443 return;
444 }
445
Byoungho Jungda10dd32023-10-06 17:03:45 +0900446 if (const auto it = mMousePointersByDisplay.find(args.displayId);
447 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
448 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
449 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900450
451 if (!mShowTouchesEnabled) {
452 return;
453 }
454
455 // Get the touch pointer controller for the device, or create one if it doesn't exist.
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000456 auto [it, controllerAdded] =
457 mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
458 if (controllerAdded) {
Arpit Singh420d0742024-04-04 11:54:20 +0000459 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000460 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900461
462 PointerControllerInterface& pc = *it->second;
463
464 const PointerCoords* coords = args.pointerCoords.data();
465 const int32_t maskedAction = MotionEvent::getActionMasked(args.action);
466 const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
467 std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
468 BitSet32 idBits;
Linnan Li45b321e2024-07-17 19:33:21 +0000469 if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL &&
470 maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900471 for (size_t i = 0; i < args.getPointerCount(); i++) {
472 if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
473 continue;
474 }
475 uint32_t id = args.pointerProperties[i].id;
476 idToIndex[id] = i;
477 idBits.markBit(id);
478 }
479 }
480 // The PointerController already handles setting spots per-display, so
481 // we do not need to manually manage display changes for touch spots for now.
482 pc.setSpots(coords, idToIndex.cbegin(), idBits, args.displayId);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000483}
484
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900485void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& args) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800486 if (!args.displayId.isValid()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900487 return;
488 }
489
490 if (args.getPointerCount() != 1) {
491 LOG(WARNING) << "Only stylus hover events with a single pointer are currently supported: "
492 << args.dump();
493 }
494
495 // Get the stylus pointer controller for the device, or create one if it doesn't exist.
Arpit Singh420d0742024-04-04 11:54:20 +0000496 auto [it, controllerAdded] =
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900497 mStylusPointersByDevice.try_emplace(args.deviceId,
498 getStylusControllerConstructor(args.displayId));
Arpit Singh420d0742024-04-04 11:54:20 +0000499 if (controllerAdded) {
500 onControllerAddedOrRemovedLocked();
501 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900502
503 PointerControllerInterface& pc = *it->second;
504
505 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
506 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
507 pc.setPosition(x, y);
508 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000509 // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
510 // immediately by a DOWN event.
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900511 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhan888993d2024-09-17 20:01:48 +0000512 pc.updatePointerIcon(mShowTouchesEnabled ? PointerIconStyle::TYPE_SPOT_HOVER
513 : PointerIconStyle::TYPE_NOT_SPECIFIED);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000514 } else if (canUnfadeOnDisplay(args.displayId)) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900515 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
516 }
517}
518
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000519void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
520 mNextListener.notify(args);
521}
522
523void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
524 mNextListener.notify(args);
525}
526
527void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
528 mNextListener.notify(args);
529}
530
531void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900532 processDeviceReset(args);
533
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000534 mNextListener.notify(args);
535}
536
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900537void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) {
Arpit Singh7918c822024-11-20 11:28:44 +0000538 std::scoped_lock _l(getLock());
Prabir Pradhan16788792023-11-08 21:07:21 +0000539 mTouchPointersByDevice.erase(args.deviceId);
540 mStylusPointersByDevice.erase(args.deviceId);
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000541 mDrawingTabletPointersByDevice.erase(args.deviceId);
Arpit Singh420d0742024-04-04 11:54:20 +0000542 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000543}
544
Arpit Singh420d0742024-04-04 11:54:20 +0000545void PointerChoreographer::onControllerAddedOrRemovedLocked() {
Arpit Singhe33845c2024-10-25 20:59:24 +0000546 if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows() &&
547 !com::android::input::flags::connected_displays_cursor()) {
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000548 return;
549 }
Arpit Singh420d0742024-04-04 11:54:20 +0000550 bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() ||
551 !mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000552
Arpit Singh7918c822024-11-20 11:28:44 +0000553 // PointerChoreographer uses Listener's lock which is already held by caller
554 base::ScopedLockAssertion assumeLocked(mWindowInfoListener->mLock);
555
556 if (requireListener && !mIsWindowInfoListenerRegistered) {
557 mIsWindowInfoListenerRegistered = true;
558 mWindowInfoListener->setInitialDisplayInfosLocked(mRegisterListener(mWindowInfoListener));
559 onPrivacySensitiveDisplaysChangedLocked(
560 mWindowInfoListener->getPrivacySensitiveDisplaysLocked());
561 } else if (!requireListener && mIsWindowInfoListenerRegistered) {
562 mIsWindowInfoListenerRegistered = false;
Arpit Singhbd49b282024-05-23 18:02:54 +0000563 mUnregisterListener(mWindowInfoListener);
Arpit Singh7918c822024-11-20 11:28:44 +0000564 } else if (requireListener) {
Arpit Singh420d0742024-04-04 11:54:20 +0000565 // controller may have been added to an existing privacy sensitive display, we need to
566 // update all controllers again
Arpit Singh7918c822024-11-20 11:28:44 +0000567 onPrivacySensitiveDisplaysChangedLocked(
568 mWindowInfoListener->getPrivacySensitiveDisplaysLocked());
Arpit Singh420d0742024-04-04 11:54:20 +0000569 }
570}
571
572void PointerChoreographer::onPrivacySensitiveDisplaysChangedLocked(
573 const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) {
574 for (auto& [_, pc] : mTouchPointersByDevice) {
575 pc->clearSkipScreenshotFlags();
576 for (auto displayId : privacySensitiveDisplays) {
577 pc->setSkipScreenshotFlagForDisplay(displayId);
578 }
579 }
580
581 for (auto& [displayId, pc] : mMousePointersByDisplay) {
582 if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
583 pc->setSkipScreenshotFlagForDisplay(displayId);
584 } else {
585 pc->clearSkipScreenshotFlags();
586 }
587 }
588
589 for (auto* pointerControllerByDevice :
590 {&mDrawingTabletPointersByDevice, &mStylusPointersByDevice}) {
591 for (auto& [_, pc] : *pointerControllerByDevice) {
592 auto displayId = pc->getDisplayId();
593 if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
594 pc->setSkipScreenshotFlagForDisplay(displayId);
595 } else {
596 pc->clearSkipScreenshotFlags();
597 }
598 }
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000599 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900600}
601
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000602void PointerChoreographer::notifyPointerCaptureChanged(
603 const NotifyPointerCaptureChangedArgs& args) {
Hiroki Sato25040232024-02-22 17:21:22 +0900604 if (args.request.isEnable()) {
Arpit Singh7918c822024-11-20 11:28:44 +0000605 std::scoped_lock _l(getLock());
Byoungho Jungda10dd32023-10-06 17:03:45 +0900606 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
607 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
608 }
609 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000610 mNextListener.notify(args);
611}
612
Arpit Singhe33845c2024-10-25 20:59:24 +0000613void PointerChoreographer::setDisplayTopology(
614 const std::unordered_map<ui::LogicalDisplayId, std::vector<AdjacentDisplay>>&
615 displayTopology) {
616 std::scoped_lock _l(getLock());
617 mTopology = displayTopology;
618}
619
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000620void PointerChoreographer::dump(std::string& dump) {
Arpit Singh7918c822024-11-20 11:28:44 +0000621 std::scoped_lock _l(getLock());
Byoungho Jungda10dd32023-10-06 17:03:45 +0900622
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000623 dump += "PointerChoreographer:\n";
Harry Cuttsebd418a2024-08-16 15:52:24 +0000624 dump += StringPrintf(INDENT "Show Touches Enabled: %s\n",
625 mShowTouchesEnabled ? "true" : "false");
626 dump += StringPrintf(INDENT "Stylus PointerIcon Enabled: %s\n",
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900627 mStylusPointerIconEnabled ? "true" : "false");
Byoungho Jungda10dd32023-10-06 17:03:45 +0900628
629 dump += INDENT "MousePointerControllers:\n";
630 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
631 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
Linnan Li13bf76a2024-05-05 19:18:02 +0800632 dump += INDENT + displayId.toString() + " : " + pointerControllerDump;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900633 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900634 dump += INDENT "TouchPointerControllers:\n";
635 for (const auto& [deviceId, touchPointerController] : mTouchPointersByDevice) {
636 std::string pointerControllerDump = addLinePrefix(touchPointerController->dump(), INDENT);
637 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
638 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900639 dump += INDENT "StylusPointerControllers:\n";
640 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
641 std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
642 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
643 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000644 dump += INDENT "DrawingTabletControllers:\n";
645 for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
646 std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT);
647 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
648 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900649 dump += "\n";
650}
651
Linnan Li13bf76a2024-05-05 19:18:02 +0800652const DisplayViewport* PointerChoreographer::findViewportByIdLocked(
653 ui::LogicalDisplayId displayId) const {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900654 for (auto& viewport : mViewports) {
655 if (viewport.displayId == displayId) {
656 return &viewport;
657 }
658 }
659 return nullptr;
660}
661
Linnan Li13bf76a2024-05-05 19:18:02 +0800662ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked(
663 ui::LogicalDisplayId associatedDisplayId) const {
664 return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900665}
666
Linnan Li13bf76a2024-05-05 19:18:02 +0800667std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
668PointerChoreographer::ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) {
669 const ui::LogicalDisplayId displayId = getTargetMouseDisplayLocked(associatedDisplayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900670
Prabir Pradhan990d8712024-03-05 00:31:36 +0000671 auto it = mMousePointersByDisplay.find(displayId);
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000672 if (it == mMousePointersByDisplay.end()) {
673 it = mMousePointersByDisplay.emplace(displayId, getMouseControllerConstructor(displayId))
674 .first;
Arpit Singh420d0742024-04-04 11:54:20 +0000675 onControllerAddedOrRemovedLocked();
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000676 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900677
678 return {displayId, *it->second};
679}
680
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900681InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000682 auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
683 [deviceId](const auto& info) { return info.getId() == deviceId; });
684 return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900685}
686
Linnan Li13bf76a2024-05-05 19:18:02 +0800687bool PointerChoreographer::canUnfadeOnDisplay(ui::LogicalDisplayId displayId) {
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000688 return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
689}
690
Arpit Singh7918c822024-11-20 11:28:44 +0000691std::mutex& PointerChoreographer::getLock() const {
692 return mWindowInfoListener->mLock;
693}
694
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000695PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() {
Linnan Li13bf76a2024-05-05 19:18:02 +0800696 std::set<ui::LogicalDisplayId /*displayId*/> mouseDisplaysToKeep;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900697 std::set<DeviceId> touchDevicesToKeep;
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900698 std::set<DeviceId> stylusDevicesToKeep;
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000699 std::set<DeviceId> drawingTabletDevicesToKeep;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900700
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000701 // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
702 // new PointerControllers if necessary.
Byoungho Jungda10dd32023-10-06 17:03:45 +0900703 for (const auto& info : mInputDeviceInfos) {
Linnan Li48f80da2024-04-22 18:38:16 +0000704 if (!info.isEnabled()) {
705 // If device is disabled, we should not keep it, and should not show pointer for
706 // disabled mouse device.
707 continue;
708 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900709 const uint32_t sources = info.getSources();
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000710 const bool isKnownMouse = mMouseDevices.count(info.getId()) != 0;
711
712 if (isMouseOrTouchpad(sources) || isKnownMouse) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800713 const ui::LogicalDisplayId displayId =
714 getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000715 mouseDisplaysToKeep.insert(displayId);
716 // For mice, show the cursor immediately when the device is first connected or
717 // when it moves to a new display.
718 auto [mousePointerIt, isNewMousePointer] =
719 mMousePointersByDisplay.try_emplace(displayId,
720 getMouseControllerConstructor(displayId));
Arpit Singh420d0742024-04-04 11:54:20 +0000721 if (isNewMousePointer) {
722 onControllerAddedOrRemovedLocked();
723 }
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000724
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000725 mMouseDevices.emplace(info.getId());
726 if ((!isKnownMouse || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000727 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
728 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900729 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900730 if (isFromSource(sources, AINPUT_SOURCE_TOUCHSCREEN) && mShowTouchesEnabled &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800731 info.getAssociatedDisplayId().isValid()) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900732 touchDevicesToKeep.insert(info.getId());
733 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900734 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && mStylusPointerIconEnabled &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800735 info.getAssociatedDisplayId().isValid()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900736 stylusDevicesToKeep.insert(info.getId());
737 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000738 if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE) &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800739 info.getAssociatedDisplayId().isValid()) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000740 drawingTabletDevicesToKeep.insert(info.getId());
741 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900742 }
743
744 // Remove PointerControllers no longer needed.
Prabir Pradhan19767602023-11-03 16:53:31 +0000745 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000746 return mouseDisplaysToKeep.find(pair.first) == mouseDisplaysToKeep.end();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900747 });
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900748 std::erase_if(mTouchPointersByDevice, [&touchDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000749 return touchDevicesToKeep.find(pair.first) == touchDevicesToKeep.end();
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900750 });
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900751 std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000752 return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900753 });
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000754 std::erase_if(mDrawingTabletPointersByDevice, [&drawingTabletDevicesToKeep](const auto& pair) {
755 return drawingTabletDevicesToKeep.find(pair.first) == drawingTabletDevicesToKeep.end();
756 });
Arpit Singh7918c822024-11-20 11:28:44 +0000757 std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(getLock()) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000758 return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
759 [id](const auto& info) { return info.getId() == id; }) ==
760 mInputDeviceInfos.end();
761 });
Byoungho Jungda10dd32023-10-06 17:03:45 +0900762
Arpit Singh420d0742024-04-04 11:54:20 +0000763 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000764
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000765 // Check if we need to notify the policy if there's a change on the pointer display ID.
766 return calculatePointerDisplayChangeToNotify();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900767}
768
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000769PointerChoreographer::PointerDisplayChange
770PointerChoreographer::calculatePointerDisplayChangeToNotify() {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700771 ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900772 FloatPoint cursorPosition = {0, 0};
773 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
774 it != mMousePointersByDisplay.end()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000775 const auto& pointerController = it->second;
776 // Use the displayId from the pointerController, because it accurately reflects whether
777 // the viewport has been added for that display. Otherwise, we would have to check if
778 // the viewport exists separately.
779 displayIdToNotify = pointerController->getDisplayId();
780 cursorPosition = pointerController->getPosition();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900781 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900782 if (mNotifiedPointerDisplayId == displayIdToNotify) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000783 return {};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900784 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900785 mNotifiedPointerDisplayId = displayIdToNotify;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000786 return {{displayIdToNotify, cursorPosition}};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900787}
788
Linnan Li13bf76a2024-05-05 19:18:02 +0800789void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000790 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900791
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000792 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000793 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000794
795 mDefaultMouseDisplayId = displayId;
796 pointerDisplayChange = updatePointerControllersLocked();
797 } // release lock
798
799 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900800}
801
802void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000803 PointerDisplayChange pointerDisplayChange;
804
805 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000806 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000807 for (const auto& viewport : viewports) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800808 const ui::LogicalDisplayId displayId = viewport.displayId;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000809 if (const auto it = mMousePointersByDisplay.find(displayId);
810 it != mMousePointersByDisplay.end()) {
811 it->second->setDisplayViewport(viewport);
812 }
813 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
814 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
815 if (info && info->getAssociatedDisplayId() == displayId) {
816 stylusPointerController->setDisplayViewport(viewport);
817 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900818 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000819 for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
820 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
821 if (info && info->getAssociatedDisplayId() == displayId) {
822 drawingTabletController->setDisplayViewport(viewport);
823 }
824 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900825 }
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000826 mViewports = viewports;
827 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
828 } // release lock
829
830 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900831}
832
833std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
Linnan Li13bf76a2024-05-05 19:18:02 +0800834 ui::LogicalDisplayId associatedDisplayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000835 std::scoped_lock _l(getLock());
Linnan Li13bf76a2024-05-05 19:18:02 +0800836 const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900837 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
838 return *viewport;
839 }
840 return std::nullopt;
841}
842
Linnan Li13bf76a2024-05-05 19:18:02 +0800843FloatPoint PointerChoreographer::getMouseCursorPosition(ui::LogicalDisplayId displayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000844 std::scoped_lock _l(getLock());
Linnan Li13bf76a2024-05-05 19:18:02 +0800845 const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900846 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
847 it != mMousePointersByDisplay.end()) {
848 return it->second->getPosition();
849 }
850 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000851}
852
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900853void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000854 PointerDisplayChange pointerDisplayChange;
855
856 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000857 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000858 if (mShowTouchesEnabled == enabled) {
859 return;
860 }
861 mShowTouchesEnabled = enabled;
862 pointerDisplayChange = updatePointerControllersLocked();
863 } // release lock
864
865 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900866}
867
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900868void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000869 PointerDisplayChange pointerDisplayChange;
870
871 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000872 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000873 if (mStylusPointerIconEnabled == enabled) {
874 return;
875 }
876 mStylusPointerIconEnabled = enabled;
877 pointerDisplayChange = updatePointerControllersLocked();
878 } // release lock
879
880 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900881}
882
Byoungho Jung99326452023-11-03 20:19:17 +0900883bool PointerChoreographer::setPointerIcon(
Linnan Li13bf76a2024-05-05 19:18:02 +0800884 std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
885 ui::LogicalDisplayId displayId, DeviceId deviceId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000886 std::scoped_lock _l(getLock());
Byoungho Jung99326452023-11-03 20:19:17 +0900887 if (deviceId < 0) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000888 LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900889 return false;
890 }
891 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
892 if (!info) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000893 LOG(WARNING) << "No input device info found for id " << deviceId
894 << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900895 return false;
896 }
897 const uint32_t sources = info->getSources();
Byoungho Jung99326452023-11-03 20:19:17 +0900898
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000899 if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE)) {
900 auto it = mDrawingTabletPointersByDevice.find(deviceId);
901 if (it != mDrawingTabletPointersByDevice.end()) {
902 setIconForController(icon, *it->second);
903 return true;
Byoungho Jung99326452023-11-03 20:19:17 +0900904 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000905 }
906 if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) {
907 auto it = mStylusPointersByDevice.find(deviceId);
908 if (it != mStylusPointersByDevice.end()) {
Prabir Pradhan888993d2024-09-17 20:01:48 +0000909 if (mShowTouchesEnabled) {
910 // If an app doesn't override the icon for the hovering stylus, show the hover icon.
911 auto* style = std::get_if<PointerIconStyle>(&icon);
912 if (style != nullptr && *style == PointerIconStyle::TYPE_NOT_SPECIFIED) {
913 *style = PointerIconStyle::TYPE_SPOT_HOVER;
914 }
915 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000916 setIconForController(icon, *it->second);
917 return true;
918 }
919 }
920 if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
921 auto it = mMousePointersByDisplay.find(displayId);
922 if (it != mMousePointersByDisplay.end()) {
923 setIconForController(icon, *it->second);
924 return true;
Byoungho Jung99326452023-11-03 20:19:17 +0900925 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000926 LOG(WARNING) << "No mouse pointer controller found for display " << displayId
927 << ", device " << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900928 return false;
929 }
Byoungho Jung99326452023-11-03 20:19:17 +0900930 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000931 LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device " << deviceId
932 << ".";
933 return false;
Byoungho Jung99326452023-11-03 20:19:17 +0900934}
935
Linnan Li13bf76a2024-05-05 19:18:02 +0800936void PointerChoreographer::setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) {
Arpit Singh7918c822024-11-20 11:28:44 +0000937 std::scoped_lock lock(getLock());
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000938 if (visible) {
939 mDisplaysWithPointersHidden.erase(displayId);
940 // We do not unfade the icons here, because we don't know when the last event happened.
941 return;
942 }
943
944 mDisplaysWithPointersHidden.emplace(displayId);
945
946 // Hide any icons that are currently visible on the display.
947 if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
948 const auto& [_, controller] = *it;
949 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
950 }
951 for (const auto& [_, controller] : mStylusPointersByDevice) {
952 if (controller->getDisplayId() == displayId) {
953 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
954 }
955 }
956}
957
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000958void PointerChoreographer::setFocusedDisplay(ui::LogicalDisplayId displayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000959 std::scoped_lock lock(getLock());
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000960 mCurrentFocusedDisplay = displayId;
961}
962
Prabir Pradhan19767602023-11-03 16:53:31 +0000963PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
Linnan Li13bf76a2024-05-05 19:18:02 +0800964 ui::LogicalDisplayId displayId) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000965 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
Arpit Singh7918c822024-11-20 11:28:44 +0000966 [this, displayId]() REQUIRES(getLock()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000967 auto pc = mPolicy.createPointerController(
968 PointerControllerInterface::ControllerType::MOUSE);
969 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
970 pc->setDisplayViewport(*viewport);
971 }
972 return pc;
973 };
974 return ConstructorDelegate(std::move(ctor));
975}
976
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900977PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor(
Linnan Li13bf76a2024-05-05 19:18:02 +0800978 ui::LogicalDisplayId displayId) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900979 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
Arpit Singh7918c822024-11-20 11:28:44 +0000980 [this, displayId]() REQUIRES(getLock()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900981 auto pc = mPolicy.createPointerController(
982 PointerControllerInterface::ControllerType::STYLUS);
983 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
984 pc->setDisplayViewport(*viewport);
985 }
986 return pc;
987 };
988 return ConstructorDelegate(std::move(ctor));
989}
990
Arpit Singhe33845c2024-10-25 20:59:24 +0000991void PointerChoreographer::populateFakeDisplayTopologyLocked(
992 const std::vector<gui::DisplayInfo>& displayInfos) {
993 if (!com::android::input::flags::connected_displays_cursor()) {
994 return;
995 }
996
997 if (displayInfos.size() == mTopology.size()) {
998 bool displaysChanged = false;
999 for (const auto& displayInfo : displayInfos) {
1000 if (mTopology.find(displayInfo.displayId) == mTopology.end()) {
1001 displaysChanged = true;
1002 break;
1003 }
1004 }
1005
1006 if (!displaysChanged) {
1007 return;
1008 }
1009 }
1010
1011 // create a fake topology assuming following order
1012 // default-display (top-edge) -> next-display (right-edge) -> next-display (right-edge) ...
Arpit Singhf0169ab2024-11-18 20:44:35 +00001013 // This also adds a 100px offset on corresponding edge for better manual testing
1014 // ┌────────┐
1015 // │ next ├─────────┐
1016 // ┌─└───────┐┤ next 2 │ ...
1017 // │ default │└─────────┘
Arpit Singhe33845c2024-10-25 20:59:24 +00001018 // └─────────┘
1019 mTopology.clear();
1020
1021 // treat default display as base, in real topology it should be the primary-display
1022 ui::LogicalDisplayId previousDisplay = ui::LogicalDisplayId::DEFAULT;
1023 for (const auto& displayInfo : displayInfos) {
1024 if (displayInfo.displayId == ui::LogicalDisplayId::DEFAULT) {
1025 continue;
1026 }
1027 if (previousDisplay == ui::LogicalDisplayId::DEFAULT) {
Arpit Singhf0169ab2024-11-18 20:44:35 +00001028 mTopology[previousDisplay].push_back(
1029 {displayInfo.displayId, DisplayPosition::TOP, 100});
Arpit Singhe33845c2024-10-25 20:59:24 +00001030 mTopology[displayInfo.displayId].push_back(
Arpit Singhf0169ab2024-11-18 20:44:35 +00001031 {previousDisplay, DisplayPosition::BOTTOM, -100});
Arpit Singhe33845c2024-10-25 20:59:24 +00001032 } else {
1033 mTopology[previousDisplay].push_back(
Arpit Singhf0169ab2024-11-18 20:44:35 +00001034 {displayInfo.displayId, DisplayPosition::RIGHT, 100});
1035 mTopology[displayInfo.displayId].push_back(
1036 {previousDisplay, DisplayPosition::LEFT, -100});
Arpit Singhe33845c2024-10-25 20:59:24 +00001037 }
1038 previousDisplay = displayInfo.displayId;
1039 }
1040
1041 // update default pointer display. In real topology it should be the primary-display
1042 if (mTopology.find(mDefaultMouseDisplayId) == mTopology.end()) {
1043 mDefaultMouseDisplayId = ui::LogicalDisplayId::DEFAULT;
1044 }
1045}
1046
Arpit Singhf0169ab2024-11-18 20:44:35 +00001047std::optional<std::pair<const DisplayViewport*, float /*offset*/>>
1048PointerChoreographer::findDestinationDisplayLocked(const ui::LogicalDisplayId sourceDisplayId,
1049 const DisplayPosition sourceBoundary,
1050 float cursorOffset) const {
1051 const auto& sourceNode = mTopology.find(sourceDisplayId);
1052 if (sourceNode == mTopology.end()) {
Arpit Singhe33845c2024-10-25 20:59:24 +00001053 // Topology is likely out of sync with viewport info, wait for it to be updated
Arpit Singhf0169ab2024-11-18 20:44:35 +00001054 LOG(WARNING) << "Source display missing from topology " << sourceDisplayId;
Arpit Singhe33845c2024-10-25 20:59:24 +00001055 return std::nullopt;
1056 }
Arpit Singhf0169ab2024-11-18 20:44:35 +00001057 for (const AdjacentDisplay& adjacentDisplay : sourceNode->second) {
Arpit Singhe33845c2024-10-25 20:59:24 +00001058 if (adjacentDisplay.position != sourceBoundary) {
1059 continue;
1060 }
1061 const DisplayViewport* destinationViewport =
1062 findViewportByIdLocked(adjacentDisplay.displayId);
1063 if (destinationViewport == nullptr) {
1064 // Topology is likely out of sync with viewport info, wait for them to be updated
1065 LOG(WARNING) << "Cannot find viewport for adjacent display "
Arpit Singhf0169ab2024-11-18 20:44:35 +00001066 << adjacentDisplay.displayId << "of source display " << sourceDisplayId;
1067 continue;
Arpit Singhe33845c2024-10-25 20:59:24 +00001068 }
Arpit Singhf0169ab2024-11-18 20:44:35 +00001069 // target position must be within target display boundary
1070 const int32_t edgeSize =
1071 sourceBoundary == DisplayPosition::TOP || sourceBoundary == DisplayPosition::BOTTOM
1072 ? (destinationViewport->logicalRight - destinationViewport->logicalLeft)
1073 : (destinationViewport->logicalBottom - destinationViewport->logicalTop);
1074 if (cursorOffset >= adjacentDisplay.offsetPx &&
1075 cursorOffset <= adjacentDisplay.offsetPx + edgeSize) {
1076 return std::make_pair(destinationViewport, adjacentDisplay.offsetPx);
1077 }
Arpit Singhe33845c2024-10-25 20:59:24 +00001078 }
1079 return std::nullopt;
1080}
1081
Arpit Singh7918c822024-11-20 11:28:44 +00001082// --- PointerChoreographer::PointerChoreographerDisplayInfoListener ---
1083
Arpit Singh4b6ad2d2024-04-04 11:54:20 +00001084void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfosChanged(
1085 const gui::WindowInfosUpdate& windowInfosUpdate) {
Arpit Singh7918c822024-11-20 11:28:44 +00001086 std::scoped_lock _l(mLock);
Arpit Singh420d0742024-04-04 11:54:20 +00001087 if (mPointerChoreographer == nullptr) {
1088 return;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +00001089 }
Arpit Singh420d0742024-04-04 11:54:20 +00001090 auto newPrivacySensitiveDisplays =
1091 getPrivacySensitiveDisplaysFromWindowInfos(windowInfosUpdate.windowInfos);
Arpit Singhe33845c2024-10-25 20:59:24 +00001092
1093 // PointerChoreographer uses Listener's lock.
1094 base::ScopedLockAssertion assumeLocked(mPointerChoreographer->getLock());
Arpit Singh420d0742024-04-04 11:54:20 +00001095 if (newPrivacySensitiveDisplays != mPrivacySensitiveDisplays) {
1096 mPrivacySensitiveDisplays = std::move(newPrivacySensitiveDisplays);
Arpit Singh7918c822024-11-20 11:28:44 +00001097 mPointerChoreographer->onPrivacySensitiveDisplaysChangedLocked(mPrivacySensitiveDisplays);
Arpit Singh420d0742024-04-04 11:54:20 +00001098 }
Arpit Singhe33845c2024-10-25 20:59:24 +00001099 mPointerChoreographer->populateFakeDisplayTopologyLocked(windowInfosUpdate.displayInfos);
Arpit Singh420d0742024-04-04 11:54:20 +00001100}
1101
Arpit Singh7918c822024-11-20 11:28:44 +00001102void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfosLocked(
Arpit Singh420d0742024-04-04 11:54:20 +00001103 const std::vector<gui::WindowInfo>& windowInfos) {
Arpit Singh420d0742024-04-04 11:54:20 +00001104 mPrivacySensitiveDisplays = getPrivacySensitiveDisplaysFromWindowInfos(windowInfos);
1105}
1106
1107std::unordered_set<ui::LogicalDisplayId /*displayId*/>
Arpit Singh7918c822024-11-20 11:28:44 +00001108PointerChoreographer::PointerChoreographerDisplayInfoListener::getPrivacySensitiveDisplaysLocked() {
Arpit Singh420d0742024-04-04 11:54:20 +00001109 return mPrivacySensitiveDisplays;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +00001110}
1111
1112void PointerChoreographer::PointerChoreographerDisplayInfoListener::
1113 onPointerChoreographerDestroyed() {
Arpit Singh7918c822024-11-20 11:28:44 +00001114 std::scoped_lock _l(mLock);
Arpit Singh4b6ad2d2024-04-04 11:54:20 +00001115 mPointerChoreographer = nullptr;
1116}
1117
Prabir Pradhanb56e92c2023-06-09 23:40:37 +00001118} // namespace android