blob: 31fbb515b220c97c50e833055a176ecc24d943d0 [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 Singhbd49b282024-05-23 18:02:54 +0000142 mRegisterListener(registerListener),
143 mUnregisterListener(unregisterListener) {}
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000144
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000145PointerChoreographer::~PointerChoreographer() {
146 std::scoped_lock _l(mLock);
147 if (mWindowInfoListener == nullptr) {
148 return;
149 }
150 mWindowInfoListener->onPointerChoreographerDestroyed();
Arpit Singhbd49b282024-05-23 18:02:54 +0000151 mUnregisterListener(mWindowInfoListener);
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000152}
153
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000154void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000155 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900156
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000157 { // acquire lock
158 std::scoped_lock _l(mLock);
159
160 mInputDeviceInfos = args.inputDeviceInfos;
161 pointerDisplayChange = updatePointerControllersLocked();
162 } // release lock
163
164 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000165 mNextListener.notify(args);
166}
167
168void PointerChoreographer::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) {
169 mNextListener.notify(args);
170}
171
172void PointerChoreographer::notifyKey(const NotifyKeyArgs& args) {
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000173 fadeMouseCursorOnKeyPress(args);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000174 mNextListener.notify(args);
175}
176
177void PointerChoreographer::notifyMotion(const NotifyMotionArgs& args) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900178 NotifyMotionArgs newArgs = processMotion(args);
179
180 mNextListener.notify(newArgs);
181}
182
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000183void PointerChoreographer::fadeMouseCursorOnKeyPress(const android::NotifyKeyArgs& args) {
184 if (args.action == AKEY_EVENT_ACTION_UP || isMetaKey(args.keyCode)) {
185 return;
186 }
187 // Meta state for these keys is ignored for dismissing cursor while typing
188 constexpr static int32_t ALLOW_FADING_META_STATE_MASK = AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON |
189 AMETA_SCROLL_LOCK_ON | AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON | AMETA_SHIFT_ON;
190 if (args.metaState & ~ALLOW_FADING_META_STATE_MASK) {
191 // Do not fade if any other meta state is active
192 return;
193 }
194 if (!mPolicy.isInputMethodConnectionActive()) {
195 return;
196 }
197
198 std::scoped_lock _l(mLock);
199 ui::LogicalDisplayId targetDisplay = args.displayId;
200 if (targetDisplay == ui::LogicalDisplayId::INVALID) {
201 targetDisplay = mCurrentFocusedDisplay;
202 }
203 auto it = mMousePointersByDisplay.find(targetDisplay);
204 if (it != mMousePointersByDisplay.end()) {
Arpit Singh849beb42024-06-06 07:14:17 +0000205 mPolicy.notifyMouseCursorFadedOnTyping();
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000206 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
207 }
208}
209
Byoungho Jungda10dd32023-10-06 17:03:45 +0900210NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& args) {
211 std::scoped_lock _l(mLock);
212
213 if (isFromMouse(args)) {
214 return processMouseEventLocked(args);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900215 } else if (isFromTouchpad(args)) {
216 return processTouchpadEventLocked(args);
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000217 } else if (isFromDrawingTablet(args)) {
218 processDrawingTabletEventLocked(args);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900219 } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
220 processStylusHoverEventLocked(args);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900221 } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900222 processTouchscreenAndStylusEventLocked(args);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900223 }
224 return args;
225}
226
227NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotionArgs& args) {
228 if (args.getPointerCount() != 1) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000229 LOG(FATAL) << "Only mouse events with a single pointer are currently supported: "
230 << args.dump();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900231 }
232
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000233 mMouseDevices.emplace(args.deviceId);
Prabir Pradhan990d8712024-03-05 00:31:36 +0000234 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900235 NotifyMotionArgs newArgs(args);
236 newArgs.displayId = displayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900237
Nergi Rahardie0a4cfe2024-03-11 13:18:59 +0900238 if (MotionEvent::isValidCursorPosition(args.xCursorPosition, args.yCursorPosition)) {
239 // This is an absolute mouse device that knows about the location of the cursor on the
240 // display, so set the cursor position to the specified location.
241 const auto [x, y] = pc.getPosition();
242 const float deltaX = args.xCursorPosition - x;
243 const float deltaY = args.yCursorPosition - y;
244 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
245 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
246 pc.setPosition(args.xCursorPosition, args.yCursorPosition);
247 } else {
248 // This is a relative mouse, so move the cursor by the specified amount.
249 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
250 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
251 pc.move(deltaX, deltaY);
252 const auto [x, y] = pc.getPosition();
253 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
254 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
255 newArgs.xCursorPosition = x;
256 newArgs.yCursorPosition = y;
257 }
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000258 if (canUnfadeOnDisplay(displayId)) {
259 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
260 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900261 return newArgs;
262}
263
Byoungho Jungee6268f2023-10-30 17:27:26 +0900264NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000265 mMouseDevices.emplace(args.deviceId);
Prabir Pradhan990d8712024-03-05 00:31:36 +0000266 auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900267
268 NotifyMotionArgs newArgs(args);
269 newArgs.displayId = displayId;
270 if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
271 // This is a movement of the mouse pointer.
272 const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
273 const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
274 pc.move(deltaX, deltaY);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000275 if (canUnfadeOnDisplay(displayId)) {
276 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
277 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900278
279 const auto [x, y] = pc.getPosition();
280 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
281 newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
282 newArgs.xCursorPosition = x;
283 newArgs.yCursorPosition = y;
284 } else {
285 // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000286 if (canUnfadeOnDisplay(displayId)) {
287 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
288 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900289
290 const auto [x, y] = pc.getPosition();
291 for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
292 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
293 args.pointerCoords[i].getX() + x);
294 newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
295 args.pointerCoords[i].getY() + y);
296 }
297 newArgs.xCursorPosition = x;
298 newArgs.yCursorPosition = y;
299 }
300 return newArgs;
301}
302
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000303void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700304 if (args.displayId == ui::LogicalDisplayId::INVALID) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000305 return;
306 }
307
308 if (args.getPointerCount() != 1) {
309 LOG(WARNING) << "Only drawing tablet events with a single pointer are currently supported: "
310 << args.dump();
311 }
312
313 // Use a mouse pointer controller for drawing tablets, or create one if it doesn't exist.
Arpit Singh420d0742024-04-04 11:54:20 +0000314 auto [it, controllerAdded] =
315 mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
316 getMouseControllerConstructor(
317 args.displayId));
318 if (controllerAdded) {
319 onControllerAddedOrRemovedLocked();
320 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000321
322 PointerControllerInterface& pc = *it->second;
323
324 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
325 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
326 pc.setPosition(x, y);
327 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
328 // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
329 // immediately by a DOWN event.
330 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
331 pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
332 } else if (canUnfadeOnDisplay(args.displayId)) {
333 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
334 }
335}
336
Byoungho Jungda10dd32023-10-06 17:03:45 +0900337/**
338 * When screen is touched, fade the mouse pointer on that display. We only call fade for
339 * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
340 * mouse device keeps moving and unfades the cursor.
341 * For touch events, we do not need to populate the cursor position.
342 */
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900343void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800344 if (!args.displayId.isValid()) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900345 return;
346 }
347
Byoungho Jungda10dd32023-10-06 17:03:45 +0900348 if (const auto it = mMousePointersByDisplay.find(args.displayId);
349 it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
350 it->second->fade(PointerControllerInterface::Transition::GRADUAL);
351 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900352
353 if (!mShowTouchesEnabled) {
354 return;
355 }
356
357 // Get the touch pointer controller for the device, or create one if it doesn't exist.
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000358 auto [it, controllerAdded] =
359 mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
360 if (controllerAdded) {
Arpit Singh420d0742024-04-04 11:54:20 +0000361 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000362 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900363
364 PointerControllerInterface& pc = *it->second;
365
366 const PointerCoords* coords = args.pointerCoords.data();
367 const int32_t maskedAction = MotionEvent::getActionMasked(args.action);
368 const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
369 std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
370 BitSet32 idBits;
371 if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL) {
372 for (size_t i = 0; i < args.getPointerCount(); i++) {
373 if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
374 continue;
375 }
376 uint32_t id = args.pointerProperties[i].id;
377 idToIndex[id] = i;
378 idBits.markBit(id);
379 }
380 }
381 // The PointerController already handles setting spots per-display, so
382 // we do not need to manually manage display changes for touch spots for now.
383 pc.setSpots(coords, idToIndex.cbegin(), idBits, args.displayId);
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000384}
385
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900386void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& args) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800387 if (!args.displayId.isValid()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900388 return;
389 }
390
391 if (args.getPointerCount() != 1) {
392 LOG(WARNING) << "Only stylus hover events with a single pointer are currently supported: "
393 << args.dump();
394 }
395
396 // Get the stylus pointer controller for the device, or create one if it doesn't exist.
Arpit Singh420d0742024-04-04 11:54:20 +0000397 auto [it, controllerAdded] =
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900398 mStylusPointersByDevice.try_emplace(args.deviceId,
399 getStylusControllerConstructor(args.displayId));
Arpit Singh420d0742024-04-04 11:54:20 +0000400 if (controllerAdded) {
401 onControllerAddedOrRemovedLocked();
402 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900403
404 PointerControllerInterface& pc = *it->second;
405
406 const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
407 const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
408 pc.setPosition(x, y);
409 if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000410 // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
411 // immediately by a DOWN event.
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900412 pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhan4b36db92024-01-03 20:56:57 +0000413 pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000414 } else if (canUnfadeOnDisplay(args.displayId)) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900415 pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
416 }
417}
418
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000419void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
420 mNextListener.notify(args);
421}
422
423void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
424 mNextListener.notify(args);
425}
426
427void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
428 mNextListener.notify(args);
429}
430
431void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900432 processDeviceReset(args);
433
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000434 mNextListener.notify(args);
435}
436
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900437void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) {
438 std::scoped_lock _l(mLock);
Prabir Pradhan16788792023-11-08 21:07:21 +0000439 mTouchPointersByDevice.erase(args.deviceId);
440 mStylusPointersByDevice.erase(args.deviceId);
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000441 mDrawingTabletPointersByDevice.erase(args.deviceId);
Arpit Singh420d0742024-04-04 11:54:20 +0000442 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000443}
444
Arpit Singh420d0742024-04-04 11:54:20 +0000445void PointerChoreographer::onControllerAddedOrRemovedLocked() {
Arpit Singhbd49b282024-05-23 18:02:54 +0000446 if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows()) {
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000447 return;
448 }
Arpit Singh420d0742024-04-04 11:54:20 +0000449 bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() ||
450 !mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000451
452 if (requireListener && mWindowInfoListener == nullptr) {
453 mWindowInfoListener = sp<PointerChoreographerDisplayInfoListener>::make(this);
Arpit Singhbd49b282024-05-23 18:02:54 +0000454 mWindowInfoListener->setInitialDisplayInfos(mRegisterListener(mWindowInfoListener));
Arpit Singh420d0742024-04-04 11:54:20 +0000455 onPrivacySensitiveDisplaysChangedLocked(mWindowInfoListener->getPrivacySensitiveDisplays());
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000456 } else if (!requireListener && mWindowInfoListener != nullptr) {
Arpit Singhbd49b282024-05-23 18:02:54 +0000457 mUnregisterListener(mWindowInfoListener);
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000458 mWindowInfoListener = nullptr;
Arpit Singh420d0742024-04-04 11:54:20 +0000459 } else if (requireListener && mWindowInfoListener != nullptr) {
460 // controller may have been added to an existing privacy sensitive display, we need to
461 // update all controllers again
462 onPrivacySensitiveDisplaysChangedLocked(mWindowInfoListener->getPrivacySensitiveDisplays());
463 }
464}
465
466void PointerChoreographer::onPrivacySensitiveDisplaysChangedLocked(
467 const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) {
468 for (auto& [_, pc] : mTouchPointersByDevice) {
469 pc->clearSkipScreenshotFlags();
470 for (auto displayId : privacySensitiveDisplays) {
471 pc->setSkipScreenshotFlagForDisplay(displayId);
472 }
473 }
474
475 for (auto& [displayId, pc] : mMousePointersByDisplay) {
476 if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
477 pc->setSkipScreenshotFlagForDisplay(displayId);
478 } else {
479 pc->clearSkipScreenshotFlags();
480 }
481 }
482
483 for (auto* pointerControllerByDevice :
484 {&mDrawingTabletPointersByDevice, &mStylusPointersByDevice}) {
485 for (auto& [_, pc] : *pointerControllerByDevice) {
486 auto displayId = pc->getDisplayId();
487 if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
488 pc->setSkipScreenshotFlagForDisplay(displayId);
489 } else {
490 pc->clearSkipScreenshotFlags();
491 }
492 }
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000493 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900494}
495
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000496void PointerChoreographer::notifyPointerCaptureChanged(
497 const NotifyPointerCaptureChangedArgs& args) {
Hiroki Sato25040232024-02-22 17:21:22 +0900498 if (args.request.isEnable()) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900499 std::scoped_lock _l(mLock);
500 for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
501 mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
502 }
503 }
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000504 mNextListener.notify(args);
505}
506
Arpit Singh420d0742024-04-04 11:54:20 +0000507void PointerChoreographer::onPrivacySensitiveDisplaysChanged(
508 const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) {
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000509 std::scoped_lock _l(mLock);
Arpit Singh420d0742024-04-04 11:54:20 +0000510 onPrivacySensitiveDisplaysChangedLocked(privacySensitiveDisplays);
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000511}
512
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000513void PointerChoreographer::dump(std::string& dump) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900514 std::scoped_lock _l(mLock);
515
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000516 dump += "PointerChoreographer:\n";
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900517 dump += StringPrintf("show touches: %s\n", mShowTouchesEnabled ? "true" : "false");
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900518 dump += StringPrintf("stylus pointer icon enabled: %s\n",
519 mStylusPointerIconEnabled ? "true" : "false");
Byoungho Jungda10dd32023-10-06 17:03:45 +0900520
521 dump += INDENT "MousePointerControllers:\n";
522 for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
523 std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
Linnan Li13bf76a2024-05-05 19:18:02 +0800524 dump += INDENT + displayId.toString() + " : " + pointerControllerDump;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900525 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900526 dump += INDENT "TouchPointerControllers:\n";
527 for (const auto& [deviceId, touchPointerController] : mTouchPointersByDevice) {
528 std::string pointerControllerDump = addLinePrefix(touchPointerController->dump(), INDENT);
529 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
530 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900531 dump += INDENT "StylusPointerControllers:\n";
532 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
533 std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
534 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
535 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000536 dump += INDENT "DrawingTabletControllers:\n";
537 for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
538 std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT);
539 dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
540 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900541 dump += "\n";
542}
543
Linnan Li13bf76a2024-05-05 19:18:02 +0800544const DisplayViewport* PointerChoreographer::findViewportByIdLocked(
545 ui::LogicalDisplayId displayId) const {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900546 for (auto& viewport : mViewports) {
547 if (viewport.displayId == displayId) {
548 return &viewport;
549 }
550 }
551 return nullptr;
552}
553
Linnan Li13bf76a2024-05-05 19:18:02 +0800554ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked(
555 ui::LogicalDisplayId associatedDisplayId) const {
556 return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900557}
558
Linnan Li13bf76a2024-05-05 19:18:02 +0800559std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
560PointerChoreographer::ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) {
561 const ui::LogicalDisplayId displayId = getTargetMouseDisplayLocked(associatedDisplayId);
Byoungho Jungee6268f2023-10-30 17:27:26 +0900562
Prabir Pradhan990d8712024-03-05 00:31:36 +0000563 auto it = mMousePointersByDisplay.find(displayId);
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000564 if (it == mMousePointersByDisplay.end()) {
565 it = mMousePointersByDisplay.emplace(displayId, getMouseControllerConstructor(displayId))
566 .first;
Arpit Singh420d0742024-04-04 11:54:20 +0000567 onControllerAddedOrRemovedLocked();
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000568 }
Byoungho Jungee6268f2023-10-30 17:27:26 +0900569
570 return {displayId, *it->second};
571}
572
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900573InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000574 auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
575 [deviceId](const auto& info) { return info.getId() == deviceId; });
576 return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900577}
578
Linnan Li13bf76a2024-05-05 19:18:02 +0800579bool PointerChoreographer::canUnfadeOnDisplay(ui::LogicalDisplayId displayId) {
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000580 return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
581}
582
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000583PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() {
Linnan Li13bf76a2024-05-05 19:18:02 +0800584 std::set<ui::LogicalDisplayId /*displayId*/> mouseDisplaysToKeep;
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900585 std::set<DeviceId> touchDevicesToKeep;
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900586 std::set<DeviceId> stylusDevicesToKeep;
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000587 std::set<DeviceId> drawingTabletDevicesToKeep;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900588
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000589 // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
590 // new PointerControllers if necessary.
Byoungho Jungda10dd32023-10-06 17:03:45 +0900591 for (const auto& info : mInputDeviceInfos) {
Linnan Li48f80da2024-04-22 18:38:16 +0000592 if (!info.isEnabled()) {
593 // If device is disabled, we should not keep it, and should not show pointer for
594 // disabled mouse device.
595 continue;
596 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900597 const uint32_t sources = info.getSources();
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000598 const bool isKnownMouse = mMouseDevices.count(info.getId()) != 0;
599
600 if (isMouseOrTouchpad(sources) || isKnownMouse) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800601 const ui::LogicalDisplayId displayId =
602 getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000603 mouseDisplaysToKeep.insert(displayId);
604 // For mice, show the cursor immediately when the device is first connected or
605 // when it moves to a new display.
606 auto [mousePointerIt, isNewMousePointer] =
607 mMousePointersByDisplay.try_emplace(displayId,
608 getMouseControllerConstructor(displayId));
Arpit Singh420d0742024-04-04 11:54:20 +0000609 if (isNewMousePointer) {
610 onControllerAddedOrRemovedLocked();
611 }
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000612
Prabir Pradhan5a31d3c2024-03-29 20:23:22 +0000613 mMouseDevices.emplace(info.getId());
614 if ((!isKnownMouse || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000615 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
616 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900617 }
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900618 if (isFromSource(sources, AINPUT_SOURCE_TOUCHSCREEN) && mShowTouchesEnabled &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800619 info.getAssociatedDisplayId().isValid()) {
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900620 touchDevicesToKeep.insert(info.getId());
621 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900622 if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && mStylusPointerIconEnabled &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800623 info.getAssociatedDisplayId().isValid()) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900624 stylusDevicesToKeep.insert(info.getId());
625 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000626 if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE) &&
Linnan Li13bf76a2024-05-05 19:18:02 +0800627 info.getAssociatedDisplayId().isValid()) {
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000628 drawingTabletDevicesToKeep.insert(info.getId());
629 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900630 }
631
632 // Remove PointerControllers no longer needed.
Prabir Pradhan19767602023-11-03 16:53:31 +0000633 std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000634 return mouseDisplaysToKeep.find(pair.first) == mouseDisplaysToKeep.end();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900635 });
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900636 std::erase_if(mTouchPointersByDevice, [&touchDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000637 return touchDevicesToKeep.find(pair.first) == touchDevicesToKeep.end();
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900638 });
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900639 std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
Prabir Pradhan16788792023-11-08 21:07:21 +0000640 return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900641 });
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000642 std::erase_if(mDrawingTabletPointersByDevice, [&drawingTabletDevicesToKeep](const auto& pair) {
643 return drawingTabletDevicesToKeep.find(pair.first) == drawingTabletDevicesToKeep.end();
644 });
Prabir Pradhan6506f6f2023-12-11 20:48:39 +0000645 std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(mLock) {
646 return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
647 [id](const auto& info) { return info.getId() == id; }) ==
648 mInputDeviceInfos.end();
649 });
Byoungho Jungda10dd32023-10-06 17:03:45 +0900650
Arpit Singh420d0742024-04-04 11:54:20 +0000651 onControllerAddedOrRemovedLocked();
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000652
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000653 // Check if we need to notify the policy if there's a change on the pointer display ID.
654 return calculatePointerDisplayChangeToNotify();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900655}
656
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000657PointerChoreographer::PointerDisplayChange
658PointerChoreographer::calculatePointerDisplayChangeToNotify() {
Siarhei Vishniakoucfbee532024-05-10 13:41:35 -0700659 ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900660 FloatPoint cursorPosition = {0, 0};
661 if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
662 it != mMousePointersByDisplay.end()) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000663 const auto& pointerController = it->second;
664 // Use the displayId from the pointerController, because it accurately reflects whether
665 // the viewport has been added for that display. Otherwise, we would have to check if
666 // the viewport exists separately.
667 displayIdToNotify = pointerController->getDisplayId();
668 cursorPosition = pointerController->getPosition();
Byoungho Jungda10dd32023-10-06 17:03:45 +0900669 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900670 if (mNotifiedPointerDisplayId == displayIdToNotify) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000671 return {};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900672 }
Byoungho Jungda10dd32023-10-06 17:03:45 +0900673 mNotifiedPointerDisplayId = displayIdToNotify;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000674 return {{displayIdToNotify, cursorPosition}};
Byoungho Jungda10dd32023-10-06 17:03:45 +0900675}
676
Linnan Li13bf76a2024-05-05 19:18:02 +0800677void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000678 PointerDisplayChange pointerDisplayChange;
Byoungho Jungda10dd32023-10-06 17:03:45 +0900679
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000680 { // acquire lock
681 std::scoped_lock _l(mLock);
682
683 mDefaultMouseDisplayId = displayId;
684 pointerDisplayChange = updatePointerControllersLocked();
685 } // release lock
686
687 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900688}
689
690void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000691 PointerDisplayChange pointerDisplayChange;
692
693 { // acquire lock
694 std::scoped_lock _l(mLock);
695 for (const auto& viewport : viewports) {
Linnan Li13bf76a2024-05-05 19:18:02 +0800696 const ui::LogicalDisplayId displayId = viewport.displayId;
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000697 if (const auto it = mMousePointersByDisplay.find(displayId);
698 it != mMousePointersByDisplay.end()) {
699 it->second->setDisplayViewport(viewport);
700 }
701 for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
702 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
703 if (info && info->getAssociatedDisplayId() == displayId) {
704 stylusPointerController->setDisplayViewport(viewport);
705 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900706 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000707 for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
708 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
709 if (info && info->getAssociatedDisplayId() == displayId) {
710 drawingTabletController->setDisplayViewport(viewport);
711 }
712 }
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900713 }
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000714 mViewports = viewports;
715 pointerDisplayChange = calculatePointerDisplayChangeToNotify();
716 } // release lock
717
718 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900719}
720
721std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
Linnan Li13bf76a2024-05-05 19:18:02 +0800722 ui::LogicalDisplayId associatedDisplayId) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900723 std::scoped_lock _l(mLock);
Linnan Li13bf76a2024-05-05 19:18:02 +0800724 const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900725 if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
726 return *viewport;
727 }
728 return std::nullopt;
729}
730
Linnan Li13bf76a2024-05-05 19:18:02 +0800731FloatPoint PointerChoreographer::getMouseCursorPosition(ui::LogicalDisplayId displayId) {
Byoungho Jungda10dd32023-10-06 17:03:45 +0900732 std::scoped_lock _l(mLock);
Linnan Li13bf76a2024-05-05 19:18:02 +0800733 const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
Byoungho Jungda10dd32023-10-06 17:03:45 +0900734 if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
735 it != mMousePointersByDisplay.end()) {
736 return it->second->getPosition();
737 }
738 return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000739}
740
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900741void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000742 PointerDisplayChange pointerDisplayChange;
743
744 { // acquire lock
745 std::scoped_lock _l(mLock);
746 if (mShowTouchesEnabled == enabled) {
747 return;
748 }
749 mShowTouchesEnabled = enabled;
750 pointerDisplayChange = updatePointerControllersLocked();
751 } // release lock
752
753 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jung6f5b16b2023-10-27 18:22:07 +0900754}
755
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900756void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
Prabir Pradhan5a51a222024-03-05 03:54:00 +0000757 PointerDisplayChange pointerDisplayChange;
758
759 { // acquire lock
760 std::scoped_lock _l(mLock);
761 if (mStylusPointerIconEnabled == enabled) {
762 return;
763 }
764 mStylusPointerIconEnabled = enabled;
765 pointerDisplayChange = updatePointerControllersLocked();
766 } // release lock
767
768 notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900769}
770
Byoungho Jung99326452023-11-03 20:19:17 +0900771bool PointerChoreographer::setPointerIcon(
Linnan Li13bf76a2024-05-05 19:18:02 +0800772 std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
773 ui::LogicalDisplayId displayId, DeviceId deviceId) {
Byoungho Jung99326452023-11-03 20:19:17 +0900774 std::scoped_lock _l(mLock);
775 if (deviceId < 0) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000776 LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900777 return false;
778 }
779 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
780 if (!info) {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000781 LOG(WARNING) << "No input device info found for id " << deviceId
782 << ". Cannot set pointer icon.";
Byoungho Jung99326452023-11-03 20:19:17 +0900783 return false;
784 }
785 const uint32_t sources = info->getSources();
Byoungho Jung99326452023-11-03 20:19:17 +0900786
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000787 if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE)) {
788 auto it = mDrawingTabletPointersByDevice.find(deviceId);
789 if (it != mDrawingTabletPointersByDevice.end()) {
790 setIconForController(icon, *it->second);
791 return true;
Byoungho Jung99326452023-11-03 20:19:17 +0900792 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000793 }
794 if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) {
795 auto it = mStylusPointersByDevice.find(deviceId);
796 if (it != mStylusPointersByDevice.end()) {
797 setIconForController(icon, *it->second);
798 return true;
799 }
800 }
801 if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
802 auto it = mMousePointersByDisplay.find(displayId);
803 if (it != mMousePointersByDisplay.end()) {
804 setIconForController(icon, *it->second);
805 return true;
Byoungho Jung99326452023-11-03 20:19:17 +0900806 } else {
Prabir Pradhan521f4fc2023-12-04 19:09:59 +0000807 LOG(WARNING) << "No mouse pointer controller found for display " << displayId
808 << ", device " << deviceId << ".";
Byoungho Jung99326452023-11-03 20:19:17 +0900809 return false;
810 }
Byoungho Jung99326452023-11-03 20:19:17 +0900811 }
Prabir Pradhan4c977a42024-03-15 16:47:37 +0000812 LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device " << deviceId
813 << ".";
814 return false;
Byoungho Jung99326452023-11-03 20:19:17 +0900815}
816
Linnan Li13bf76a2024-05-05 19:18:02 +0800817void PointerChoreographer::setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) {
Prabir Pradhan502ddbd2024-01-19 02:22:38 +0000818 std::scoped_lock lock(mLock);
819 if (visible) {
820 mDisplaysWithPointersHidden.erase(displayId);
821 // We do not unfade the icons here, because we don't know when the last event happened.
822 return;
823 }
824
825 mDisplaysWithPointersHidden.emplace(displayId);
826
827 // Hide any icons that are currently visible on the display.
828 if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
829 const auto& [_, controller] = *it;
830 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
831 }
832 for (const auto& [_, controller] : mStylusPointersByDevice) {
833 if (controller->getDisplayId() == displayId) {
834 controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
835 }
836 }
837}
838
Arpit Singhb65e2bd2024-06-03 09:48:16 +0000839void PointerChoreographer::setFocusedDisplay(ui::LogicalDisplayId displayId) {
840 std::scoped_lock lock(mLock);
841 mCurrentFocusedDisplay = displayId;
842}
843
Prabir Pradhan19767602023-11-03 16:53:31 +0000844PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
Linnan Li13bf76a2024-05-05 19:18:02 +0800845 ui::LogicalDisplayId displayId) {
Prabir Pradhan19767602023-11-03 16:53:31 +0000846 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
847 [this, displayId]() REQUIRES(mLock) {
848 auto pc = mPolicy.createPointerController(
849 PointerControllerInterface::ControllerType::MOUSE);
850 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
851 pc->setDisplayViewport(*viewport);
852 }
853 return pc;
854 };
855 return ConstructorDelegate(std::move(ctor));
856}
857
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900858PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor(
Linnan Li13bf76a2024-05-05 19:18:02 +0800859 ui::LogicalDisplayId displayId) {
Byoungho Jungd6fe27b2023-10-27 20:49:38 +0900860 std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
861 [this, displayId]() REQUIRES(mLock) {
862 auto pc = mPolicy.createPointerController(
863 PointerControllerInterface::ControllerType::STYLUS);
864 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
865 pc->setDisplayViewport(*viewport);
866 }
867 return pc;
868 };
869 return ConstructorDelegate(std::move(ctor));
870}
871
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000872void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfosChanged(
873 const gui::WindowInfosUpdate& windowInfosUpdate) {
874 std::scoped_lock _l(mListenerLock);
Arpit Singh420d0742024-04-04 11:54:20 +0000875 if (mPointerChoreographer == nullptr) {
876 return;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000877 }
Arpit Singh420d0742024-04-04 11:54:20 +0000878 auto newPrivacySensitiveDisplays =
879 getPrivacySensitiveDisplaysFromWindowInfos(windowInfosUpdate.windowInfos);
880 if (newPrivacySensitiveDisplays != mPrivacySensitiveDisplays) {
881 mPrivacySensitiveDisplays = std::move(newPrivacySensitiveDisplays);
882 mPointerChoreographer->onPrivacySensitiveDisplaysChanged(mPrivacySensitiveDisplays);
883 }
884}
885
886void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfos(
887 const std::vector<gui::WindowInfo>& windowInfos) {
888 std::scoped_lock _l(mListenerLock);
889 mPrivacySensitiveDisplays = getPrivacySensitiveDisplaysFromWindowInfos(windowInfos);
890}
891
892std::unordered_set<ui::LogicalDisplayId /*displayId*/>
893PointerChoreographer::PointerChoreographerDisplayInfoListener::getPrivacySensitiveDisplays() {
894 std::scoped_lock _l(mListenerLock);
895 return mPrivacySensitiveDisplays;
Arpit Singh4b6ad2d2024-04-04 11:54:20 +0000896}
897
898void PointerChoreographer::PointerChoreographerDisplayInfoListener::
899 onPointerChoreographerDestroyed() {
900 std::scoped_lock _l(mListenerLock);
901 mPointerChoreographer = nullptr;
902}
903
Prabir Pradhanb56e92c2023-06-09 23:40:37 +0000904} // namespace android