blob: a67df58fe47f11245ddbb88f98c574c02bf977bb [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 Singh7918c822024-11-20 11:28:44 +0000208 std::scoped_lock _l(getLock());
Byoungho Jungda10dd32023-10-06 17:03:45 +0900209
Liana Kazanova (xWF)ff80e302024-11-18 19:14:42 +0000210 if (isFromMouse(args)) {
211 return processMouseEventLocked(args);
212 } else if (isFromTouchpad(args)) {
213 return processTouchpadEventLocked(args);
214 } else if (isFromDrawingTablet(args)) {
215 processDrawingTabletEventLocked(args);
216 } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
217 processStylusHoverEventLocked(args);
218 } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
219 processTouchscreenAndStylusEventLocked(args);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900220 }
Liana Kazanova (xWF)ff80e302024-11-18 19:14:42 +0000221 return args;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900222}
223
224NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotionArgs& args) {
225 if (args.getPointerCount() != 1) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000226 LOG(FATAL) << "Only mouse events with a single pointer are currently supported: "
227 << args.dump();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900228 }
229
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000230 mMouseDevices.emplace(args.deviceId);
Prabir Pradhan990d8712024-03-05 00:31:36 +0000231 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900232 NotifyMotionArgs newArgs(args);
233 newArgs.displayId = displayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900234
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900235 if (MotionEvent::isValidCursorPosition(args.xCursorPosition, args.yCursorPosition)) {
236 // This is an absolute mouse device that knows about the location of the cursor on the
237 // display, so set the cursor position to the specified location.
238 const auto [x, y] = pc.getPosition();
239 const float deltaX = args.xCursorPosition - x;
240 const float deltaY = args.yCursorPosition - y;
241 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
242 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
243 pc.setPosition(args.xCursorPosition, args.yCursorPosition);
244 } else {
245 // This is a relative mouse, so move the cursor by the specified amount.
Liana Kazanova (xWF)ff80e302024-11-18 19:14:42 +0000246 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
247 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
248 pc.move(deltaX, deltaY);
249 const auto [x, y] = pc.getPosition();
250 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
251 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
252 newArgs.xCursorPosition = x;
253 newArgs.yCursorPosition = y;
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900254 }
Liana Kazanova (xWF)ff80e302024-11-18 19:14:42 +0000255 if (canUnfadeOnDisplay(displayId)) {
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000256 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
257 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900258 return newArgs;
259}
260
Byoungho Jungee6268f2023-10-30 17:27:26 +0900261NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000262 mMouseDevices.emplace(args.deviceId);
Prabir Pradhan990d8712024-03-05 00:31:36 +0000263 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900264
265 NotifyMotionArgs newArgs(args);
266 newArgs.displayId = displayId;
267 if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
268 // This is a movement of the mouse pointer.
Liana Kazanova (xWF)ff80e302024-11-18 19:14:42 +0000269 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
270 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
271 pc.move(deltaX, deltaY);
272 if (canUnfadeOnDisplay(displayId)) {
273 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
274 }
275
276 const auto [x, y] = pc.getPosition();
277 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
278 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
279 newArgs.xCursorPosition = x;
280 newArgs.yCursorPosition = y;
Byoungho Jungee6268f2023-10-30 17:27:26 +0900281 } else {
282 // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
Liana Kazanova (xWF)ff80e302024-11-18 19:14:42 +0000283 if (canUnfadeOnDisplay(displayId)) {
284 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
285 }
286
Byoungho Jungee6268f2023-10-30 17:27:26 +0900287 const auto [x, y] = pc.getPosition();
288 for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
289 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
290 args.pointerCoords[i].getX() + x);
291 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
292 args.pointerCoords[i].getY() + y);
293 }
294 newArgs.xCursorPosition = x;
295 newArgs.yCursorPosition = y;
296 }
297 return newArgs;
298}
299
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000300void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700301 if (args.displayId == ui::LogicalDisplayId::INVALID) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000302 return;
303 }
304
305 if (args.getPointerCount() != 1) {
306 LOG(WARNING) << "Only drawing tablet events with a single pointer are currently supported: "
307 << args.dump();
308 }
309
310 // Use a mouse pointer controller for drawing tablets, or create one if it doesn't exist.
Arpit Singh420d0742024-04-04 11:54:20 +0000311 auto [it, controllerAdded] =
312 mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
313 getMouseControllerConstructor(
314 args.displayId));
315 if (controllerAdded) {
316 onControllerAddedOrRemovedLocked();
317 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000318
319 PointerControllerInterface& pc = *it->second;
320
321 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
322 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
323 pc.setPosition(x, y);
324 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
325 // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
326 // immediately by a DOWN event.
327 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
328 pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
329 } else if (canUnfadeOnDisplay(args.displayId)) {
330 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
331 }
332}
333
Byoungho Jungda10dd32023-10-06 17:03:45 +0900334/**
335 * When screen is touched, fade the mouse pointer on that display. We only call fade for
336 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
337 * mouse device keeps moving and unfades the cursor.
338 * For touch events, we do not need to populate the cursor position.
339 */
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900340void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800341 if (!args.displayId.isValid()) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900342 return;
343 }
344
Byoungho Jungda10dd32023-10-06 17:03:45 +0900345 if (const auto it = mMousePointersByDisplay.find(args.displayId);
346 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
347 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
348 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900349
350 if (!mShowTouchesEnabled) {
351 return;
352 }
353
354 // Get the touch pointer controller for the device, or create one if it doesn't exist.
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000355 auto [it, controllerAdded] =
356 mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
357 if (controllerAdded) {
Arpit Singh420d0742024-04-04 11:54:20 +0000358 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000359 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900360
361 PointerControllerInterface& pc = *it->second;
362
363 const PointerCoords* coords = args.pointerCoords.data();
364 const int32_t maskedAction = MotionEvent::getActionMasked(args.action);
365 const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
366 std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
367 BitSet32 idBits;
Linnan Li45b321e2024-07-17 19:33:21 +0000368 if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL &&
369 maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900370 for (size_t i = 0; i < args.getPointerCount(); i++) {
371 if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
372 continue;
373 }
374 uint32_t id = args.pointerProperties[i].id;
375 idToIndex[id] = i;
376 idBits.markBit(id);
377 }
378 }
379 // The PointerController already handles setting spots per-display, so
380 // we do not need to manually manage display changes for touch spots for now.
381 pc.setSpots(coords, idToIndex.cbegin(), idBits, args.displayId);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000382}
383
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900384void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& args) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800385 if (!args.displayId.isValid()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900386 return;
387 }
388
389 if (args.getPointerCount() != 1) {
390 LOG(WARNING) << "Only stylus hover events with a single pointer are currently supported: "
391 << args.dump();
392 }
393
394 // Get the stylus pointer controller for the device, or create one if it doesn't exist.
Arpit Singh420d0742024-04-04 11:54:20 +0000395 auto [it, controllerAdded] =
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900396 mStylusPointersByDevice.try_emplace(args.deviceId,
397 getStylusControllerConstructor(args.displayId));
Arpit Singh420d0742024-04-04 11:54:20 +0000398 if (controllerAdded) {
399 onControllerAddedOrRemovedLocked();
400 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900401
402 PointerControllerInterface& pc = *it->second;
403
404 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
405 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
406 pc.setPosition(x, y);
407 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000408 // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
409 // immediately by a DOWN event.
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900410 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhan888993d2024-09-17 20:01:48 +0000411 pc.updatePointerIcon(mShowTouchesEnabled ? PointerIconStyle::TYPE_SPOT_HOVER
412 : PointerIconStyle::TYPE_NOT_SPECIFIED);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000413 } else if (canUnfadeOnDisplay(args.displayId)) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900414 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
415 }
416}
417
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000418void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
419 mNextListener.notify(args);
420}
421
422void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
423 mNextListener.notify(args);
424}
425
426void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
427 mNextListener.notify(args);
428}
429
430void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900431 processDeviceReset(args);
432
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000433 mNextListener.notify(args);
434}
435
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900436void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) {
Arpit Singh7918c822024-11-20 11:28:44 +0000437 std::scoped_lock _l(getLock());
Prabir Pradhan16788792023-11-08 21:07:21 +0000438 mTouchPointersByDevice.erase(args.deviceId);
439 mStylusPointersByDevice.erase(args.deviceId);
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000440 mDrawingTabletPointersByDevice.erase(args.deviceId);
Arpit Singh420d0742024-04-04 11:54:20 +0000441 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000442}
443
Arpit Singh420d0742024-04-04 11:54:20 +0000444void PointerChoreographer::onControllerAddedOrRemovedLocked() {
Liana Kazanova (xWF)ff80e302024-11-18 19:14:42 +0000445 if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows()) {
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000446 return;
447 }
Arpit Singh420d0742024-04-04 11:54:20 +0000448 bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() ||
449 !mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000450
Arpit Singh7918c822024-11-20 11:28:44 +0000451 // PointerChoreographer uses Listener's lock which is already held by caller
452 base::ScopedLockAssertion assumeLocked(mWindowInfoListener->mLock);
453
454 if (requireListener && !mIsWindowInfoListenerRegistered) {
455 mIsWindowInfoListenerRegistered = true;
456 mWindowInfoListener->setInitialDisplayInfosLocked(mRegisterListener(mWindowInfoListener));
457 onPrivacySensitiveDisplaysChangedLocked(
458 mWindowInfoListener->getPrivacySensitiveDisplaysLocked());
459 } else if (!requireListener && mIsWindowInfoListenerRegistered) {
460 mIsWindowInfoListenerRegistered = false;
Arpit Singhbd49b282024-05-23 18:02:54 +0000461 mUnregisterListener(mWindowInfoListener);
Arpit Singh7918c822024-11-20 11:28:44 +0000462 } else if (requireListener) {
Arpit Singh420d0742024-04-04 11:54:20 +0000463 // controller may have been added to an existing privacy sensitive display, we need to
464 // update all controllers again
Arpit Singh7918c822024-11-20 11:28:44 +0000465 onPrivacySensitiveDisplaysChangedLocked(
466 mWindowInfoListener->getPrivacySensitiveDisplaysLocked());
Arpit Singh420d0742024-04-04 11:54:20 +0000467 }
468}
469
470void PointerChoreographer::onPrivacySensitiveDisplaysChangedLocked(
471 const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) {
472 for (auto& [_, pc] : mTouchPointersByDevice) {
473 pc->clearSkipScreenshotFlags();
474 for (auto displayId : privacySensitiveDisplays) {
475 pc->setSkipScreenshotFlagForDisplay(displayId);
476 }
477 }
478
479 for (auto& [displayId, pc] : mMousePointersByDisplay) {
480 if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
481 pc->setSkipScreenshotFlagForDisplay(displayId);
482 } else {
483 pc->clearSkipScreenshotFlags();
484 }
485 }
486
487 for (auto* pointerControllerByDevice :
488 {&mDrawingTabletPointersByDevice, &mStylusPointersByDevice}) {
489 for (auto& [_, pc] : *pointerControllerByDevice) {
490 auto displayId = pc->getDisplayId();
491 if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
492 pc->setSkipScreenshotFlagForDisplay(displayId);
493 } else {
494 pc->clearSkipScreenshotFlags();
495 }
496 }
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000497 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900498}
499
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000500void PointerChoreographer::notifyPointerCaptureChanged(
501 const NotifyPointerCaptureChangedArgs& args) {
Hiroki Sato25040232024-02-22 17:21:22 +0900502 if (args.request.isEnable()) {
Arpit Singh7918c822024-11-20 11:28:44 +0000503 std::scoped_lock _l(getLock());
Byoungho Jungda10dd32023-10-06 17:03:45 +0900504 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
505 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
506 }
507 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000508 mNextListener.notify(args);
509}
510
511void PointerChoreographer::dump(std::string& dump) {
Arpit Singh7918c822024-11-20 11:28:44 +0000512 std::scoped_lock _l(getLock());
Byoungho Jungda10dd32023-10-06 17:03:45 +0900513
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000514 dump += "PointerChoreographer:\n";
Harry Cuttsebd418a2024-08-16 15:52:24 +0000515 dump += StringPrintf(INDENT "Show Touches Enabled: %s\n",
516 mShowTouchesEnabled ? "true" : "false");
517 dump += StringPrintf(INDENT "Stylus PointerIcon Enabled: %s\n",
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900518 mStylusPointerIconEnabled ? "true" : "false");
Byoungho Jungda10dd32023-10-06 17:03:45 +0900519
520 dump += INDENT "MousePointerControllers:\n";
521 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
522 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
Linnan Li13bf76a2024-05-05 19:18:02 +0800523 dump += INDENT + displayId.toString() + " : " + pointerControllerDump;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900524 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900525 dump += INDENT "TouchPointerControllers:\n";
526 for (const auto& [deviceId, touchPointerController] : mTouchPointersByDevice) {
527 std::string pointerControllerDump = addLinePrefix(touchPointerController->dump(), INDENT);
528 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
529 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900530 dump += INDENT "StylusPointerControllers:\n";
531 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
532 std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
533 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
534 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000535 dump += INDENT "DrawingTabletControllers:\n";
536 for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
537 std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT);
538 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
539 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900540 dump += "\n";
541}
542
Linnan Li13bf76a2024-05-05 19:18:02 +0800543const DisplayViewport* PointerChoreographer::findViewportByIdLocked(
544 ui::LogicalDisplayId displayId) const {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900545 for (auto& viewport : mViewports) {
546 if (viewport.displayId == displayId) {
547 return &viewport;
548 }
549 }
550 return nullptr;
551}
552
Linnan Li13bf76a2024-05-05 19:18:02 +0800553ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked(
554 ui::LogicalDisplayId associatedDisplayId) const {
555 return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900556}
557
Linnan Li13bf76a2024-05-05 19:18:02 +0800558std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
559PointerChoreographer::ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) {
560 const ui::LogicalDisplayId displayId = getTargetMouseDisplayLocked(associatedDisplayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900561
Prabir Pradhan990d8712024-03-05 00:31:36 +0000562 auto it = mMousePointersByDisplay.find(displayId);
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000563 if (it == mMousePointersByDisplay.end()) {
564 it = mMousePointersByDisplay.emplace(displayId, getMouseControllerConstructor(displayId))
565 .first;
Arpit Singh420d0742024-04-04 11:54:20 +0000566 onControllerAddedOrRemovedLocked();
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000567 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900568
569 return {displayId, *it->second};
570}
571
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900572InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000573 auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
574 [deviceId](const auto& info) { return info.getId() == deviceId; });
575 return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900576}
577
Linnan Li13bf76a2024-05-05 19:18:02 +0800578bool PointerChoreographer::canUnfadeOnDisplay(ui::LogicalDisplayId displayId) {
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000579 return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
580}
581
Arpit Singh7918c822024-11-20 11:28:44 +0000582std::mutex& PointerChoreographer::getLock() const {
583 return mWindowInfoListener->mLock;
584}
585
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000586PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() {
Linnan Li13bf76a2024-05-05 19:18:02 +0800587 std::set<ui::LogicalDisplayId /*displayId*/> mouseDisplaysToKeep;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900588 std::set<DeviceId> touchDevicesToKeep;
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900589 std::set<DeviceId> stylusDevicesToKeep;
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000590 std::set<DeviceId> drawingTabletDevicesToKeep;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900591
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000592 // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
593 // new PointerControllers if necessary.
Byoungho Jungda10dd32023-10-06 17:03:45 +0900594 for (const auto& info : mInputDeviceInfos) {
Linnan Li48f80da2024-04-22 18:38:16 +0000595 if (!info.isEnabled()) {
596 // If device is disabled, we should not keep it, and should not show pointer for
597 // disabled mouse device.
598 continue;
599 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900600 const uint32_t sources = info.getSources();
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000601 const bool isKnownMouse = mMouseDevices.count(info.getId()) != 0;
602
603 if (isMouseOrTouchpad(sources) || isKnownMouse) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800604 const ui::LogicalDisplayId displayId =
605 getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000606 mouseDisplaysToKeep.insert(displayId);
607 // For mice, show the cursor immediately when the device is first connected or
608 // when it moves to a new display.
609 auto [mousePointerIt, isNewMousePointer] =
610 mMousePointersByDisplay.try_emplace(displayId,
611 getMouseControllerConstructor(displayId));
Arpit Singh420d0742024-04-04 11:54:20 +0000612 if (isNewMousePointer) {
613 onControllerAddedOrRemovedLocked();
614 }
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000615
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000616 mMouseDevices.emplace(info.getId());
617 if ((!isKnownMouse || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000618 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
619 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900620 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900621 if (isFromSource(sources, AINPUT_SOURCE_TOUCHSCREEN) && mShowTouchesEnabled &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800622 info.getAssociatedDisplayId().isValid()) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900623 touchDevicesToKeep.insert(info.getId());
624 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900625 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && mStylusPointerIconEnabled &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800626 info.getAssociatedDisplayId().isValid()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900627 stylusDevicesToKeep.insert(info.getId());
628 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000629 if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE) &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800630 info.getAssociatedDisplayId().isValid()) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000631 drawingTabletDevicesToKeep.insert(info.getId());
632 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900633 }
634
635 // Remove PointerControllers no longer needed.
Prabir Pradhan19767602023-11-03 16:53:31 +0000636 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000637 return mouseDisplaysToKeep.find(pair.first) == mouseDisplaysToKeep.end();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900638 });
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900639 std::erase_if(mTouchPointersByDevice, [&touchDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000640 return touchDevicesToKeep.find(pair.first) == touchDevicesToKeep.end();
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900641 });
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900642 std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000643 return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900644 });
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000645 std::erase_if(mDrawingTabletPointersByDevice, [&drawingTabletDevicesToKeep](const auto& pair) {
646 return drawingTabletDevicesToKeep.find(pair.first) == drawingTabletDevicesToKeep.end();
647 });
Arpit Singh7918c822024-11-20 11:28:44 +0000648 std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(getLock()) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000649 return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
650 [id](const auto& info) { return info.getId() == id; }) ==
651 mInputDeviceInfos.end();
652 });
Byoungho Jungda10dd32023-10-06 17:03:45 +0900653
Arpit Singh420d0742024-04-04 11:54:20 +0000654 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000655
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000656 // Check if we need to notify the policy if there's a change on the pointer display ID.
657 return calculatePointerDisplayChangeToNotify();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900658}
659
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000660PointerChoreographer::PointerDisplayChange
661PointerChoreographer::calculatePointerDisplayChangeToNotify() {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700662 ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900663 FloatPoint cursorPosition = {0, 0};
664 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
665 it != mMousePointersByDisplay.end()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000666 const auto& pointerController = it->second;
667 // Use the displayId from the pointerController, because it accurately reflects whether
668 // the viewport has been added for that display. Otherwise, we would have to check if
669 // the viewport exists separately.
670 displayIdToNotify = pointerController->getDisplayId();
671 cursorPosition = pointerController->getPosition();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900672 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900673 if (mNotifiedPointerDisplayId == displayIdToNotify) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000674 return {};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900675 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900676 mNotifiedPointerDisplayId = displayIdToNotify;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000677 return {{displayIdToNotify, cursorPosition}};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900678}
679
Linnan Li13bf76a2024-05-05 19:18:02 +0800680void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000681 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900682
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000683 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000684 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000685
686 mDefaultMouseDisplayId = displayId;
687 pointerDisplayChange = updatePointerControllersLocked();
688 } // release lock
689
690 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900691}
692
693void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000694 PointerDisplayChange pointerDisplayChange;
695
696 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000697 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000698 for (const auto& viewport : viewports) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800699 const ui::LogicalDisplayId displayId = viewport.displayId;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000700 if (const auto it = mMousePointersByDisplay.find(displayId);
701 it != mMousePointersByDisplay.end()) {
702 it->second->setDisplayViewport(viewport);
703 }
704 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
705 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
706 if (info && info->getAssociatedDisplayId() == displayId) {
707 stylusPointerController->setDisplayViewport(viewport);
708 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900709 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000710 for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
711 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
712 if (info && info->getAssociatedDisplayId() == displayId) {
713 drawingTabletController->setDisplayViewport(viewport);
714 }
715 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900716 }
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000717 mViewports = viewports;
718 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
719 } // release lock
720
721 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900722}
723
724std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
Linnan Li13bf76a2024-05-05 19:18:02 +0800725 ui::LogicalDisplayId associatedDisplayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000726 std::scoped_lock _l(getLock());
Linnan Li13bf76a2024-05-05 19:18:02 +0800727 const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900728 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
729 return *viewport;
730 }
731 return std::nullopt;
732}
733
Linnan Li13bf76a2024-05-05 19:18:02 +0800734FloatPoint PointerChoreographer::getMouseCursorPosition(ui::LogicalDisplayId displayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000735 std::scoped_lock _l(getLock());
Linnan Li13bf76a2024-05-05 19:18:02 +0800736 const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900737 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
738 it != mMousePointersByDisplay.end()) {
739 return it->second->getPosition();
740 }
741 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000742}
743
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900744void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000745 PointerDisplayChange pointerDisplayChange;
746
747 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000748 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000749 if (mShowTouchesEnabled == enabled) {
750 return;
751 }
752 mShowTouchesEnabled = enabled;
753 pointerDisplayChange = updatePointerControllersLocked();
754 } // release lock
755
756 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900757}
758
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900759void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000760 PointerDisplayChange pointerDisplayChange;
761
762 { // acquire lock
Arpit Singh7918c822024-11-20 11:28:44 +0000763 std::scoped_lock _l(getLock());
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000764 if (mStylusPointerIconEnabled == enabled) {
765 return;
766 }
767 mStylusPointerIconEnabled = enabled;
768 pointerDisplayChange = updatePointerControllersLocked();
769 } // release lock
770
771 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900772}
773
Byoungho Jung99326452023-11-03 20:19:17 +0900774bool PointerChoreographer::setPointerIcon(
Linnan Li13bf76a2024-05-05 19:18:02 +0800775 std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
776 ui::LogicalDisplayId displayId, DeviceId deviceId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000777 std::scoped_lock _l(getLock());
Byoungho Jung99326452023-11-03 20:19:17 +0900778 if (deviceId < 0) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000779 LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900780 return false;
781 }
782 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
783 if (!info) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000784 LOG(WARNING) << "No input device info found for id " << deviceId
785 << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900786 return false;
787 }
788 const uint32_t sources = info->getSources();
Byoungho Jung99326452023-11-03 20:19:17 +0900789
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000790 if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE)) {
791 auto it = mDrawingTabletPointersByDevice.find(deviceId);
792 if (it != mDrawingTabletPointersByDevice.end()) {
793 setIconForController(icon, *it->second);
794 return true;
Byoungho Jung99326452023-11-03 20:19:17 +0900795 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000796 }
797 if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) {
798 auto it = mStylusPointersByDevice.find(deviceId);
799 if (it != mStylusPointersByDevice.end()) {
Prabir Pradhan888993d2024-09-17 20:01:48 +0000800 if (mShowTouchesEnabled) {
801 // If an app doesn't override the icon for the hovering stylus, show the hover icon.
802 auto* style = std::get_if<PointerIconStyle>(&icon);
803 if (style != nullptr && *style == PointerIconStyle::TYPE_NOT_SPECIFIED) {
804 *style = PointerIconStyle::TYPE_SPOT_HOVER;
805 }
806 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000807 setIconForController(icon, *it->second);
808 return true;
809 }
810 }
811 if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
812 auto it = mMousePointersByDisplay.find(displayId);
813 if (it != mMousePointersByDisplay.end()) {
814 setIconForController(icon, *it->second);
815 return true;
Byoungho Jung99326452023-11-03 20:19:17 +0900816 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000817 LOG(WARNING) << "No mouse pointer controller found for display " << displayId
818 << ", device " << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900819 return false;
820 }
Byoungho Jung99326452023-11-03 20:19:17 +0900821 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000822 LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device " << deviceId
823 << ".";
824 return false;
Byoungho Jung99326452023-11-03 20:19:17 +0900825}
826
Linnan Li13bf76a2024-05-05 19:18:02 +0800827void PointerChoreographer::setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) {
Arpit Singh7918c822024-11-20 11:28:44 +0000828 std::scoped_lock lock(getLock());
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000829 if (visible) {
830 mDisplaysWithPointersHidden.erase(displayId);
831 // We do not unfade the icons here, because we don't know when the last event happened.
832 return;
833 }
834
835 mDisplaysWithPointersHidden.emplace(displayId);
836
837 // Hide any icons that are currently visible on the display.
838 if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
839 const auto& [_, controller] = *it;
840 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
841 }
842 for (const auto& [_, controller] : mStylusPointersByDevice) {
843 if (controller->getDisplayId() == displayId) {
844 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
845 }
846 }
847}
848
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000849void PointerChoreographer::setFocusedDisplay(ui::LogicalDisplayId displayId) {
Arpit Singh7918c822024-11-20 11:28:44 +0000850 std::scoped_lock lock(getLock());
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000851 mCurrentFocusedDisplay = displayId;
852}
853
Prabir Pradhan19767602023-11-03 16:53:31 +0000854PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
Linnan Li13bf76a2024-05-05 19:18:02 +0800855 ui::LogicalDisplayId displayId) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000856 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
Arpit Singh7918c822024-11-20 11:28:44 +0000857 [this, displayId]() REQUIRES(getLock()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000858 auto pc = mPolicy.createPointerController(
859 PointerControllerInterface::ControllerType::MOUSE);
860 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
861 pc->setDisplayViewport(*viewport);
862 }
863 return pc;
864 };
865 return ConstructorDelegate(std::move(ctor));
866}
867
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900868PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor(
Linnan Li13bf76a2024-05-05 19:18:02 +0800869 ui::LogicalDisplayId displayId) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900870 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
Arpit Singh7918c822024-11-20 11:28:44 +0000871 [this, displayId]() REQUIRES(getLock()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900872 auto pc = mPolicy.createPointerController(
873 PointerControllerInterface::ControllerType::STYLUS);
874 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
875 pc->setDisplayViewport(*viewport);
876 }
877 return pc;
878 };
879 return ConstructorDelegate(std::move(ctor));
880}
881
Arpit Singh7918c822024-11-20 11:28:44 +0000882// --- PointerChoreographer::PointerChoreographerDisplayInfoListener ---
883
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000884void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfosChanged(
885 const gui::WindowInfosUpdate& windowInfosUpdate) {
Arpit Singh7918c822024-11-20 11:28:44 +0000886 std::scoped_lock _l(mLock);
Arpit Singh420d0742024-04-04 11:54:20 +0000887 if (mPointerChoreographer == nullptr) {
888 return;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000889 }
Arpit Singh420d0742024-04-04 11:54:20 +0000890 auto newPrivacySensitiveDisplays =
891 getPrivacySensitiveDisplaysFromWindowInfos(windowInfosUpdate.windowInfos);
892 if (newPrivacySensitiveDisplays != mPrivacySensitiveDisplays) {
893 mPrivacySensitiveDisplays = std::move(newPrivacySensitiveDisplays);
Arpit Singh7918c822024-11-20 11:28:44 +0000894 // PointerChoreographer uses Listener's lock.
895 base::ScopedLockAssertion assumeLocked(mPointerChoreographer->getLock());
896 mPointerChoreographer->onPrivacySensitiveDisplaysChangedLocked(mPrivacySensitiveDisplays);
Arpit Singh420d0742024-04-04 11:54:20 +0000897 }
898}
899
Arpit Singh7918c822024-11-20 11:28:44 +0000900void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfosLocked(
Arpit Singh420d0742024-04-04 11:54:20 +0000901 const std::vector<gui::WindowInfo>& windowInfos) {
Arpit Singh420d0742024-04-04 11:54:20 +0000902 mPrivacySensitiveDisplays = getPrivacySensitiveDisplaysFromWindowInfos(windowInfos);
903}
904
905std::unordered_set<ui::LogicalDisplayId /*displayId*/>
Arpit Singh7918c822024-11-20 11:28:44 +0000906PointerChoreographer::PointerChoreographerDisplayInfoListener::getPrivacySensitiveDisplaysLocked() {
Arpit Singh420d0742024-04-04 11:54:20 +0000907 return mPrivacySensitiveDisplays;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000908}
909
910void PointerChoreographer::PointerChoreographerDisplayInfoListener::
911 onPointerChoreographerDestroyed() {
Arpit Singh7918c822024-11-20 11:28:44 +0000912 std::scoped_lock _l(mLock);
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000913 mPointerChoreographer = nullptr;
914}
915
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000916} // namespace android