xref: /aosp_15_r20/frameworks/native/services/inputflinger/PointerChoreographer.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2023 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "PointerChoreographer"
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <android-base/logging.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <com_android_input_flags.h>
21*38e8c45fSAndroid Build Coastguard Worker #if defined(__ANDROID__)
22*38e8c45fSAndroid Build Coastguard Worker #include <gui/SurfaceComposerClient.h>
23*38e8c45fSAndroid Build Coastguard Worker #endif
24*38e8c45fSAndroid Build Coastguard Worker #include <input/Keyboard.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <input/PrintTools.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <unordered_set>
27*38e8c45fSAndroid Build Coastguard Worker 
28*38e8c45fSAndroid Build Coastguard Worker #include "PointerChoreographer.h"
29*38e8c45fSAndroid Build Coastguard Worker 
30*38e8c45fSAndroid Build Coastguard Worker #define INDENT "  "
31*38e8c45fSAndroid Build Coastguard Worker 
32*38e8c45fSAndroid Build Coastguard Worker namespace android {
33*38e8c45fSAndroid Build Coastguard Worker 
34*38e8c45fSAndroid Build Coastguard Worker namespace {
35*38e8c45fSAndroid Build Coastguard Worker 
isFromMouse(const NotifyMotionArgs & args)36*38e8c45fSAndroid Build Coastguard Worker bool isFromMouse(const NotifyMotionArgs& args) {
37*38e8c45fSAndroid Build Coastguard Worker     return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
38*38e8c45fSAndroid Build Coastguard Worker             args.pointerProperties[0].toolType == ToolType::MOUSE;
39*38e8c45fSAndroid Build Coastguard Worker }
40*38e8c45fSAndroid Build Coastguard Worker 
isFromTouchpad(const NotifyMotionArgs & args)41*38e8c45fSAndroid Build Coastguard Worker bool isFromTouchpad(const NotifyMotionArgs& args) {
42*38e8c45fSAndroid Build Coastguard Worker     return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
43*38e8c45fSAndroid Build Coastguard Worker             args.pointerProperties[0].toolType == ToolType::FINGER;
44*38e8c45fSAndroid Build Coastguard Worker }
45*38e8c45fSAndroid Build Coastguard Worker 
isFromDrawingTablet(const NotifyMotionArgs & args)46*38e8c45fSAndroid Build Coastguard Worker bool isFromDrawingTablet(const NotifyMotionArgs& args) {
47*38e8c45fSAndroid Build Coastguard Worker     return isFromSource(args.source, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS) &&
48*38e8c45fSAndroid Build Coastguard Worker             isStylusToolType(args.pointerProperties[0].toolType);
49*38e8c45fSAndroid Build Coastguard Worker }
50*38e8c45fSAndroid Build Coastguard Worker 
isHoverAction(int32_t action)51*38e8c45fSAndroid Build Coastguard Worker bool isHoverAction(int32_t action) {
52*38e8c45fSAndroid Build Coastguard Worker     return action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
53*38e8c45fSAndroid Build Coastguard Worker             action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT;
54*38e8c45fSAndroid Build Coastguard Worker }
55*38e8c45fSAndroid Build Coastguard Worker 
isStylusHoverEvent(const NotifyMotionArgs & args)56*38e8c45fSAndroid Build Coastguard Worker bool isStylusHoverEvent(const NotifyMotionArgs& args) {
57*38e8c45fSAndroid Build Coastguard Worker     return isStylusEvent(args.source, args.pointerProperties) && isHoverAction(args.action);
58*38e8c45fSAndroid Build Coastguard Worker }
59*38e8c45fSAndroid Build Coastguard Worker 
isMouseOrTouchpad(uint32_t sources)60*38e8c45fSAndroid Build Coastguard Worker bool isMouseOrTouchpad(uint32_t sources) {
61*38e8c45fSAndroid Build Coastguard Worker     // Check if this is a mouse or touchpad, but not a drawing tablet.
62*38e8c45fSAndroid Build Coastguard Worker     return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
63*38e8c45fSAndroid Build Coastguard Worker             (isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
64*38e8c45fSAndroid Build Coastguard Worker              !isFromSource(sources, AINPUT_SOURCE_STYLUS));
65*38e8c45fSAndroid Build Coastguard Worker }
66*38e8c45fSAndroid Build Coastguard Worker 
notifyPointerDisplayChange(std::optional<std::tuple<ui::LogicalDisplayId,vec2>> change,PointerChoreographerPolicyInterface & policy)67*38e8c45fSAndroid Build Coastguard Worker inline void notifyPointerDisplayChange(std::optional<std::tuple<ui::LogicalDisplayId, vec2>> change,
68*38e8c45fSAndroid Build Coastguard Worker                                        PointerChoreographerPolicyInterface& policy) {
69*38e8c45fSAndroid Build Coastguard Worker     if (!change) {
70*38e8c45fSAndroid Build Coastguard Worker         return;
71*38e8c45fSAndroid Build Coastguard Worker     }
72*38e8c45fSAndroid Build Coastguard Worker     const auto& [displayId, cursorPosition] = *change;
73*38e8c45fSAndroid Build Coastguard Worker     policy.notifyPointerDisplayIdChanged(displayId, cursorPosition);
74*38e8c45fSAndroid Build Coastguard Worker }
75*38e8c45fSAndroid Build Coastguard Worker 
setIconForController(const std::variant<std::unique_ptr<SpriteIcon>,PointerIconStyle> & icon,PointerControllerInterface & controller)76*38e8c45fSAndroid Build Coastguard Worker void setIconForController(const std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle>& icon,
77*38e8c45fSAndroid Build Coastguard Worker                           PointerControllerInterface& controller) {
78*38e8c45fSAndroid Build Coastguard Worker     if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
79*38e8c45fSAndroid Build Coastguard Worker         if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
80*38e8c45fSAndroid Build Coastguard Worker             LOG(FATAL) << "SpriteIcon should not be null";
81*38e8c45fSAndroid Build Coastguard Worker         }
82*38e8c45fSAndroid Build Coastguard Worker         controller.setCustomPointerIcon(*std::get<std::unique_ptr<SpriteIcon>>(icon));
83*38e8c45fSAndroid Build Coastguard Worker     } else {
84*38e8c45fSAndroid Build Coastguard Worker         controller.updatePointerIcon(std::get<PointerIconStyle>(icon));
85*38e8c45fSAndroid Build Coastguard Worker     }
86*38e8c45fSAndroid Build Coastguard Worker }
87*38e8c45fSAndroid Build Coastguard Worker 
88*38e8c45fSAndroid Build Coastguard Worker // filters and returns a set of privacy sensitive displays that are currently visible.
getPrivacySensitiveDisplaysFromWindowInfos(const std::vector<gui::WindowInfo> & windowInfos)89*38e8c45fSAndroid Build Coastguard Worker std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysFromWindowInfos(
90*38e8c45fSAndroid Build Coastguard Worker         const std::vector<gui::WindowInfo>& windowInfos) {
91*38e8c45fSAndroid Build Coastguard Worker     std::unordered_set<ui::LogicalDisplayId> privacySensitiveDisplays;
92*38e8c45fSAndroid Build Coastguard Worker     for (const auto& windowInfo : windowInfos) {
93*38e8c45fSAndroid Build Coastguard Worker         if (!windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE) &&
94*38e8c45fSAndroid Build Coastguard Worker             windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY)) {
95*38e8c45fSAndroid Build Coastguard Worker             privacySensitiveDisplays.insert(windowInfo.displayId);
96*38e8c45fSAndroid Build Coastguard Worker         }
97*38e8c45fSAndroid Build Coastguard Worker     }
98*38e8c45fSAndroid Build Coastguard Worker     return privacySensitiveDisplays;
99*38e8c45fSAndroid Build Coastguard Worker }
100*38e8c45fSAndroid Build Coastguard Worker 
101*38e8c45fSAndroid Build Coastguard Worker } // namespace
102*38e8c45fSAndroid Build Coastguard Worker 
103*38e8c45fSAndroid Build Coastguard Worker // --- PointerChoreographer ---
104*38e8c45fSAndroid Build Coastguard Worker 
PointerChoreographer(InputListenerInterface & inputListener,PointerChoreographerPolicyInterface & policy)105*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::PointerChoreographer(InputListenerInterface& inputListener,
106*38e8c45fSAndroid Build Coastguard Worker                                            PointerChoreographerPolicyInterface& policy)
107*38e8c45fSAndroid Build Coastguard Worker       : PointerChoreographer(
108*38e8c45fSAndroid Build Coastguard Worker                 inputListener, policy,
109*38e8c45fSAndroid Build Coastguard Worker                 [](const sp<android::gui::WindowInfosListener>& listener) {
110*38e8c45fSAndroid Build Coastguard Worker                     auto initialInfo = std::make_pair(std::vector<android::gui::WindowInfo>{},
111*38e8c45fSAndroid Build Coastguard Worker                                                       std::vector<android::gui::DisplayInfo>{});
112*38e8c45fSAndroid Build Coastguard Worker #if defined(__ANDROID__)
113*38e8c45fSAndroid Build Coastguard Worker                     SurfaceComposerClient::getDefault()->addWindowInfosListener(listener,
114*38e8c45fSAndroid Build Coastguard Worker                                                                                 &initialInfo);
115*38e8c45fSAndroid Build Coastguard Worker #endif
116*38e8c45fSAndroid Build Coastguard Worker                     return initialInfo.first;
117*38e8c45fSAndroid Build Coastguard Worker                 },
__anon0aae248f0302(const sp<android::gui::WindowInfosListener>& listener) 118*38e8c45fSAndroid Build Coastguard Worker                 [](const sp<android::gui::WindowInfosListener>& listener) {
119*38e8c45fSAndroid Build Coastguard Worker #if defined(__ANDROID__)
120*38e8c45fSAndroid Build Coastguard Worker                     SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
121*38e8c45fSAndroid Build Coastguard Worker #endif
122*38e8c45fSAndroid Build Coastguard Worker                 }) {
123*38e8c45fSAndroid Build Coastguard Worker }
124*38e8c45fSAndroid Build Coastguard Worker 
PointerChoreographer(android::InputListenerInterface & listener,android::PointerChoreographerPolicyInterface & policy,const android::PointerChoreographer::WindowListenerRegisterConsumer & registerListener,const android::PointerChoreographer::WindowListenerUnregisterConsumer & unregisterListener)125*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::PointerChoreographer(
126*38e8c45fSAndroid Build Coastguard Worker         android::InputListenerInterface& listener,
127*38e8c45fSAndroid Build Coastguard Worker         android::PointerChoreographerPolicyInterface& policy,
128*38e8c45fSAndroid Build Coastguard Worker         const android::PointerChoreographer::WindowListenerRegisterConsumer& registerListener,
129*38e8c45fSAndroid Build Coastguard Worker         const android::PointerChoreographer::WindowListenerUnregisterConsumer& unregisterListener)
130*38e8c45fSAndroid Build Coastguard Worker       : mTouchControllerConstructor([this]() {
131*38e8c45fSAndroid Build Coastguard Worker             return mPolicy.createPointerController(
132*38e8c45fSAndroid Build Coastguard Worker                     PointerControllerInterface::ControllerType::TOUCH);
133*38e8c45fSAndroid Build Coastguard Worker         }),
134*38e8c45fSAndroid Build Coastguard Worker         mNextListener(listener),
135*38e8c45fSAndroid Build Coastguard Worker         mPolicy(policy),
136*38e8c45fSAndroid Build Coastguard Worker         mDefaultMouseDisplayId(ui::LogicalDisplayId::DEFAULT),
137*38e8c45fSAndroid Build Coastguard Worker         mNotifiedPointerDisplayId(ui::LogicalDisplayId::INVALID),
138*38e8c45fSAndroid Build Coastguard Worker         mShowTouchesEnabled(false),
139*38e8c45fSAndroid Build Coastguard Worker         mStylusPointerIconEnabled(false),
140*38e8c45fSAndroid Build Coastguard Worker         mCurrentFocusedDisplay(ui::LogicalDisplayId::DEFAULT),
141*38e8c45fSAndroid Build Coastguard Worker         mIsWindowInfoListenerRegistered(false),
142*38e8c45fSAndroid Build Coastguard Worker         mWindowInfoListener(sp<PointerChoreographerDisplayInfoListener>::make(this)),
143*38e8c45fSAndroid Build Coastguard Worker         mRegisterListener(registerListener),
144*38e8c45fSAndroid Build Coastguard Worker         mUnregisterListener(unregisterListener) {}
145*38e8c45fSAndroid Build Coastguard Worker 
~PointerChoreographer()146*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::~PointerChoreographer() {
147*38e8c45fSAndroid Build Coastguard Worker     if (mIsWindowInfoListenerRegistered) {
148*38e8c45fSAndroid Build Coastguard Worker         mUnregisterListener(mWindowInfoListener);
149*38e8c45fSAndroid Build Coastguard Worker         mIsWindowInfoListenerRegistered = false;
150*38e8c45fSAndroid Build Coastguard Worker     }
151*38e8c45fSAndroid Build Coastguard Worker     mWindowInfoListener->onPointerChoreographerDestroyed();
152*38e8c45fSAndroid Build Coastguard Worker }
153*38e8c45fSAndroid Build Coastguard Worker 
notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs & args)154*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
155*38e8c45fSAndroid Build Coastguard Worker     PointerDisplayChange pointerDisplayChange;
156*38e8c45fSAndroid Build Coastguard Worker 
157*38e8c45fSAndroid Build Coastguard Worker     { // acquire lock
158*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(getLock());
159*38e8c45fSAndroid Build Coastguard Worker 
160*38e8c45fSAndroid Build Coastguard Worker         mInputDeviceInfos = args.inputDeviceInfos;
161*38e8c45fSAndroid Build Coastguard Worker         pointerDisplayChange = updatePointerControllersLocked();
162*38e8c45fSAndroid Build Coastguard Worker     } // release lock
163*38e8c45fSAndroid Build Coastguard Worker 
164*38e8c45fSAndroid Build Coastguard Worker     notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
165*38e8c45fSAndroid Build Coastguard Worker     mNextListener.notify(args);
166*38e8c45fSAndroid Build Coastguard Worker }
167*38e8c45fSAndroid Build Coastguard Worker 
notifyKey(const NotifyKeyArgs & args)168*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::notifyKey(const NotifyKeyArgs& args) {
169*38e8c45fSAndroid Build Coastguard Worker     fadeMouseCursorOnKeyPress(args);
170*38e8c45fSAndroid Build Coastguard Worker     mNextListener.notify(args);
171*38e8c45fSAndroid Build Coastguard Worker }
172*38e8c45fSAndroid Build Coastguard Worker 
notifyMotion(const NotifyMotionArgs & args)173*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::notifyMotion(const NotifyMotionArgs& args) {
174*38e8c45fSAndroid Build Coastguard Worker     NotifyMotionArgs newArgs = processMotion(args);
175*38e8c45fSAndroid Build Coastguard Worker 
176*38e8c45fSAndroid Build Coastguard Worker     mNextListener.notify(newArgs);
177*38e8c45fSAndroid Build Coastguard Worker }
178*38e8c45fSAndroid Build Coastguard Worker 
fadeMouseCursorOnKeyPress(const android::NotifyKeyArgs & args)179*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::fadeMouseCursorOnKeyPress(const android::NotifyKeyArgs& args) {
180*38e8c45fSAndroid Build Coastguard Worker     if (args.action == AKEY_EVENT_ACTION_UP || isMetaKey(args.keyCode)) {
181*38e8c45fSAndroid Build Coastguard Worker         return;
182*38e8c45fSAndroid Build Coastguard Worker     }
183*38e8c45fSAndroid Build Coastguard Worker     // Meta state for these keys is ignored for dismissing cursor while typing
184*38e8c45fSAndroid Build Coastguard Worker     constexpr static int32_t ALLOW_FADING_META_STATE_MASK = AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON |
185*38e8c45fSAndroid Build Coastguard Worker             AMETA_SCROLL_LOCK_ON | AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON | AMETA_SHIFT_ON;
186*38e8c45fSAndroid Build Coastguard Worker     if (args.metaState & ~ALLOW_FADING_META_STATE_MASK) {
187*38e8c45fSAndroid Build Coastguard Worker         // Do not fade if any other meta state is active
188*38e8c45fSAndroid Build Coastguard Worker         return;
189*38e8c45fSAndroid Build Coastguard Worker     }
190*38e8c45fSAndroid Build Coastguard Worker     if (!mPolicy.isInputMethodConnectionActive()) {
191*38e8c45fSAndroid Build Coastguard Worker         return;
192*38e8c45fSAndroid Build Coastguard Worker     }
193*38e8c45fSAndroid Build Coastguard Worker 
194*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(getLock());
195*38e8c45fSAndroid Build Coastguard Worker     ui::LogicalDisplayId targetDisplay = args.displayId;
196*38e8c45fSAndroid Build Coastguard Worker     if (targetDisplay == ui::LogicalDisplayId::INVALID) {
197*38e8c45fSAndroid Build Coastguard Worker         targetDisplay = mCurrentFocusedDisplay;
198*38e8c45fSAndroid Build Coastguard Worker     }
199*38e8c45fSAndroid Build Coastguard Worker     auto it = mMousePointersByDisplay.find(targetDisplay);
200*38e8c45fSAndroid Build Coastguard Worker     if (it != mMousePointersByDisplay.end()) {
201*38e8c45fSAndroid Build Coastguard Worker         mPolicy.notifyMouseCursorFadedOnTyping();
202*38e8c45fSAndroid Build Coastguard Worker         it->second->fade(PointerControllerInterface::Transition::GRADUAL);
203*38e8c45fSAndroid Build Coastguard Worker     }
204*38e8c45fSAndroid Build Coastguard Worker }
205*38e8c45fSAndroid Build Coastguard Worker 
processMotion(const NotifyMotionArgs & args)206*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& args) {
207*38e8c45fSAndroid Build Coastguard Worker     NotifyMotionArgs newArgs(args);
208*38e8c45fSAndroid Build Coastguard Worker     PointerDisplayChange pointerDisplayChange;
209*38e8c45fSAndroid Build Coastguard Worker     { // acquire lock
210*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(getLock());
211*38e8c45fSAndroid Build Coastguard Worker         if (isFromMouse(args)) {
212*38e8c45fSAndroid Build Coastguard Worker             newArgs = processMouseEventLocked(args);
213*38e8c45fSAndroid Build Coastguard Worker             pointerDisplayChange = calculatePointerDisplayChangeToNotify();
214*38e8c45fSAndroid Build Coastguard Worker         } else if (isFromTouchpad(args)) {
215*38e8c45fSAndroid Build Coastguard Worker             newArgs = processTouchpadEventLocked(args);
216*38e8c45fSAndroid Build Coastguard Worker             pointerDisplayChange = calculatePointerDisplayChangeToNotify();
217*38e8c45fSAndroid Build Coastguard Worker         } else if (isFromDrawingTablet(args)) {
218*38e8c45fSAndroid Build Coastguard Worker             processDrawingTabletEventLocked(args);
219*38e8c45fSAndroid Build Coastguard Worker         } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
220*38e8c45fSAndroid Build Coastguard Worker             processStylusHoverEventLocked(args);
221*38e8c45fSAndroid Build Coastguard Worker         } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
222*38e8c45fSAndroid Build Coastguard Worker             processTouchscreenAndStylusEventLocked(args);
223*38e8c45fSAndroid Build Coastguard Worker         }
224*38e8c45fSAndroid Build Coastguard Worker     } // release lock
225*38e8c45fSAndroid Build Coastguard Worker 
226*38e8c45fSAndroid Build Coastguard Worker     if (pointerDisplayChange) {
227*38e8c45fSAndroid Build Coastguard Worker         // pointer display may have changed if mouse crossed display boundary
228*38e8c45fSAndroid Build Coastguard Worker         notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
229*38e8c45fSAndroid Build Coastguard Worker     }
230*38e8c45fSAndroid Build Coastguard Worker     return newArgs;
231*38e8c45fSAndroid Build Coastguard Worker }
232*38e8c45fSAndroid Build Coastguard Worker 
processMouseEventLocked(const NotifyMotionArgs & args)233*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotionArgs& args) {
234*38e8c45fSAndroid Build Coastguard Worker     if (args.getPointerCount() != 1) {
235*38e8c45fSAndroid Build Coastguard Worker         LOG(FATAL) << "Only mouse events with a single pointer are currently supported: "
236*38e8c45fSAndroid Build Coastguard Worker                    << args.dump();
237*38e8c45fSAndroid Build Coastguard Worker     }
238*38e8c45fSAndroid Build Coastguard Worker 
239*38e8c45fSAndroid Build Coastguard Worker     mMouseDevices.emplace(args.deviceId);
240*38e8c45fSAndroid Build Coastguard Worker     auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
241*38e8c45fSAndroid Build Coastguard Worker     NotifyMotionArgs newArgs(args);
242*38e8c45fSAndroid Build Coastguard Worker     newArgs.displayId = displayId;
243*38e8c45fSAndroid Build Coastguard Worker 
244*38e8c45fSAndroid Build Coastguard Worker     if (MotionEvent::isValidCursorPosition(args.xCursorPosition, args.yCursorPosition)) {
245*38e8c45fSAndroid Build Coastguard Worker         // This is an absolute mouse device that knows about the location of the cursor on the
246*38e8c45fSAndroid Build Coastguard Worker         // display, so set the cursor position to the specified location.
247*38e8c45fSAndroid Build Coastguard Worker         const auto position = pc.getPosition();
248*38e8c45fSAndroid Build Coastguard Worker         const float deltaX = args.xCursorPosition - position.x;
249*38e8c45fSAndroid Build Coastguard Worker         const float deltaY = args.yCursorPosition - position.y;
250*38e8c45fSAndroid Build Coastguard Worker         newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
251*38e8c45fSAndroid Build Coastguard Worker         newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
252*38e8c45fSAndroid Build Coastguard Worker         pc.setPosition(args.xCursorPosition, args.yCursorPosition);
253*38e8c45fSAndroid Build Coastguard Worker     } else {
254*38e8c45fSAndroid Build Coastguard Worker         // This is a relative mouse, so move the cursor by the specified amount.
255*38e8c45fSAndroid Build Coastguard Worker         processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc);
256*38e8c45fSAndroid Build Coastguard Worker     }
257*38e8c45fSAndroid Build Coastguard Worker     // Note displayId may have changed if the cursor moved to a different display
258*38e8c45fSAndroid Build Coastguard Worker     if (canUnfadeOnDisplay(newArgs.displayId)) {
259*38e8c45fSAndroid Build Coastguard Worker         pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
260*38e8c45fSAndroid Build Coastguard Worker     }
261*38e8c45fSAndroid Build Coastguard Worker     return newArgs;
262*38e8c45fSAndroid Build Coastguard Worker }
263*38e8c45fSAndroid Build Coastguard Worker 
processTouchpadEventLocked(const NotifyMotionArgs & args)264*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMotionArgs& args) {
265*38e8c45fSAndroid Build Coastguard Worker     mMouseDevices.emplace(args.deviceId);
266*38e8c45fSAndroid Build Coastguard Worker     auto [displayId, pc] = ensureMouseControllerLocked(args.displayId);
267*38e8c45fSAndroid Build Coastguard Worker 
268*38e8c45fSAndroid Build Coastguard Worker     NotifyMotionArgs newArgs(args);
269*38e8c45fSAndroid Build Coastguard Worker     newArgs.displayId = displayId;
270*38e8c45fSAndroid Build Coastguard Worker     if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) {
271*38e8c45fSAndroid Build Coastguard Worker         // This is a movement of the mouse pointer.
272*38e8c45fSAndroid Build Coastguard Worker         processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc);
273*38e8c45fSAndroid Build Coastguard Worker     } else {
274*38e8c45fSAndroid Build Coastguard Worker         // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
275*38e8c45fSAndroid Build Coastguard Worker         const auto position = pc.getPosition();
276*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
277*38e8c45fSAndroid Build Coastguard Worker             newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
278*38e8c45fSAndroid Build Coastguard Worker                                                   args.pointerCoords[i].getX() + position.x);
279*38e8c45fSAndroid Build Coastguard Worker             newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
280*38e8c45fSAndroid Build Coastguard Worker                                                   args.pointerCoords[i].getY() + position.y);
281*38e8c45fSAndroid Build Coastguard Worker         }
282*38e8c45fSAndroid Build Coastguard Worker         newArgs.xCursorPosition = position.x;
283*38e8c45fSAndroid Build Coastguard Worker         newArgs.yCursorPosition = position.y;
284*38e8c45fSAndroid Build Coastguard Worker     }
285*38e8c45fSAndroid Build Coastguard Worker 
286*38e8c45fSAndroid Build Coastguard Worker     // Note displayId may have changed if the cursor moved to a different display
287*38e8c45fSAndroid Build Coastguard Worker     if (canUnfadeOnDisplay(newArgs.displayId)) {
288*38e8c45fSAndroid Build Coastguard Worker         pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
289*38e8c45fSAndroid Build Coastguard Worker     }
290*38e8c45fSAndroid Build Coastguard Worker     return newArgs;
291*38e8c45fSAndroid Build Coastguard Worker }
292*38e8c45fSAndroid Build Coastguard Worker 
processPointerDeviceMotionEventLocked(NotifyMotionArgs & newArgs,PointerControllerInterface & pc)293*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::processPointerDeviceMotionEventLocked(NotifyMotionArgs& newArgs,
294*38e8c45fSAndroid Build Coastguard Worker                                                                  PointerControllerInterface& pc) {
295*38e8c45fSAndroid Build Coastguard Worker     const float deltaX = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
296*38e8c45fSAndroid Build Coastguard Worker     const float deltaY = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
297*38e8c45fSAndroid Build Coastguard Worker 
298*38e8c45fSAndroid Build Coastguard Worker     vec2 unconsumedDelta = pc.move(deltaX, deltaY);
299*38e8c45fSAndroid Build Coastguard Worker     if (com::android::input::flags::connected_displays_cursor() &&
300*38e8c45fSAndroid Build Coastguard Worker         (std::abs(unconsumedDelta.x) > 0 || std::abs(unconsumedDelta.y) > 0)) {
301*38e8c45fSAndroid Build Coastguard Worker         handleUnconsumedDeltaLocked(pc, unconsumedDelta);
302*38e8c45fSAndroid Build Coastguard Worker         // pointer may have moved to a different viewport
303*38e8c45fSAndroid Build Coastguard Worker         newArgs.displayId = pc.getDisplayId();
304*38e8c45fSAndroid Build Coastguard Worker     }
305*38e8c45fSAndroid Build Coastguard Worker 
306*38e8c45fSAndroid Build Coastguard Worker     const auto position = pc.getPosition();
307*38e8c45fSAndroid Build Coastguard Worker     newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, position.x);
308*38e8c45fSAndroid Build Coastguard Worker     newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, position.y);
309*38e8c45fSAndroid Build Coastguard Worker     newArgs.xCursorPosition = position.x;
310*38e8c45fSAndroid Build Coastguard Worker     newArgs.yCursorPosition = position.y;
311*38e8c45fSAndroid Build Coastguard Worker }
312*38e8c45fSAndroid Build Coastguard Worker 
handleUnconsumedDeltaLocked(PointerControllerInterface & pc,const vec2 & unconsumedDelta)313*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterface& pc,
314*38e8c45fSAndroid Build Coastguard Worker                                                        const vec2& unconsumedDelta) {
315*38e8c45fSAndroid Build Coastguard Worker     // Display topology is in rotated coordinate space and Pointer controller returns and expects
316*38e8c45fSAndroid Build Coastguard Worker     // values in the un-rotated coordinate space. So we need to transform delta and cursor position
317*38e8c45fSAndroid Build Coastguard Worker     // back to the rotated coordinate space to lookup adjacent display in the display topology.
318*38e8c45fSAndroid Build Coastguard Worker     const auto& sourceDisplayTransform = pc.getDisplayTransform();
319*38e8c45fSAndroid Build Coastguard Worker     const vec2 rotatedUnconsumedDelta =
320*38e8c45fSAndroid Build Coastguard Worker             transformWithoutTranslation(sourceDisplayTransform, unconsumedDelta);
321*38e8c45fSAndroid Build Coastguard Worker     const vec2 cursorPosition = pc.getPosition();
322*38e8c45fSAndroid Build Coastguard Worker     const vec2 rotatedCursorPosition = sourceDisplayTransform.transform(cursorPosition);
323*38e8c45fSAndroid Build Coastguard Worker 
324*38e8c45fSAndroid Build Coastguard Worker     // To find out the boundary that cursor is crossing we are checking delta in x and y direction
325*38e8c45fSAndroid Build Coastguard Worker     // respectively. This prioritizes x direction over y.
326*38e8c45fSAndroid Build Coastguard Worker     // In practise, majority of cases we only have non-zero values in either x or y coordinates,
327*38e8c45fSAndroid Build Coastguard Worker     // except sometimes near the corners.
328*38e8c45fSAndroid Build Coastguard Worker     // In these cases this behaviour is not noticeable. We also do not apply unconsumed delta on
329*38e8c45fSAndroid Build Coastguard Worker     // the destination display for the same reason.
330*38e8c45fSAndroid Build Coastguard Worker     DisplayPosition sourceBoundary;
331*38e8c45fSAndroid Build Coastguard Worker     float cursorOffset = 0.0f;
332*38e8c45fSAndroid Build Coastguard Worker     if (rotatedUnconsumedDelta.x > 0) {
333*38e8c45fSAndroid Build Coastguard Worker         sourceBoundary = DisplayPosition::RIGHT;
334*38e8c45fSAndroid Build Coastguard Worker         cursorOffset = rotatedCursorPosition.y;
335*38e8c45fSAndroid Build Coastguard Worker     } else if (rotatedUnconsumedDelta.x < 0) {
336*38e8c45fSAndroid Build Coastguard Worker         sourceBoundary = DisplayPosition::LEFT;
337*38e8c45fSAndroid Build Coastguard Worker         cursorOffset = rotatedCursorPosition.y;
338*38e8c45fSAndroid Build Coastguard Worker     } else if (rotatedUnconsumedDelta.y > 0) {
339*38e8c45fSAndroid Build Coastguard Worker         sourceBoundary = DisplayPosition::BOTTOM;
340*38e8c45fSAndroid Build Coastguard Worker         cursorOffset = rotatedCursorPosition.x;
341*38e8c45fSAndroid Build Coastguard Worker     } else {
342*38e8c45fSAndroid Build Coastguard Worker         sourceBoundary = DisplayPosition::TOP;
343*38e8c45fSAndroid Build Coastguard Worker         cursorOffset = rotatedCursorPosition.x;
344*38e8c45fSAndroid Build Coastguard Worker     }
345*38e8c45fSAndroid Build Coastguard Worker 
346*38e8c45fSAndroid Build Coastguard Worker     const ui::LogicalDisplayId sourceDisplayId = pc.getDisplayId();
347*38e8c45fSAndroid Build Coastguard Worker     std::optional<std::pair<const DisplayViewport*, float /*offset*/>> destination =
348*38e8c45fSAndroid Build Coastguard Worker             findDestinationDisplayLocked(sourceDisplayId, sourceBoundary, cursorOffset);
349*38e8c45fSAndroid Build Coastguard Worker     if (!destination.has_value()) {
350*38e8c45fSAndroid Build Coastguard Worker         // No matching adjacent display
351*38e8c45fSAndroid Build Coastguard Worker         return;
352*38e8c45fSAndroid Build Coastguard Worker     }
353*38e8c45fSAndroid Build Coastguard Worker 
354*38e8c45fSAndroid Build Coastguard Worker     const DisplayViewport& destinationViewport = *destination->first;
355*38e8c45fSAndroid Build Coastguard Worker     const float destinationOffset = destination->second;
356*38e8c45fSAndroid Build Coastguard Worker     if (mMousePointersByDisplay.find(destinationViewport.displayId) !=
357*38e8c45fSAndroid Build Coastguard Worker         mMousePointersByDisplay.end()) {
358*38e8c45fSAndroid Build Coastguard Worker         LOG(FATAL) << "A cursor already exists on destination display"
359*38e8c45fSAndroid Build Coastguard Worker                    << destinationViewport.displayId;
360*38e8c45fSAndroid Build Coastguard Worker     }
361*38e8c45fSAndroid Build Coastguard Worker     mDefaultMouseDisplayId = destinationViewport.displayId;
362*38e8c45fSAndroid Build Coastguard Worker     auto pcNode = mMousePointersByDisplay.extract(sourceDisplayId);
363*38e8c45fSAndroid Build Coastguard Worker     pcNode.key() = destinationViewport.displayId;
364*38e8c45fSAndroid Build Coastguard Worker     mMousePointersByDisplay.insert(std::move(pcNode));
365*38e8c45fSAndroid Build Coastguard Worker 
366*38e8c45fSAndroid Build Coastguard Worker     // Before updating the viewport and moving the cursor to appropriate location in the destination
367*38e8c45fSAndroid Build Coastguard Worker     // viewport, we need to temporarily hide the cursor. This will prevent it from appearing at the
368*38e8c45fSAndroid Build Coastguard Worker     // center of the display in any intermediate frames.
369*38e8c45fSAndroid Build Coastguard Worker     pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
370*38e8c45fSAndroid Build Coastguard Worker     pc.setDisplayViewport(destinationViewport);
371*38e8c45fSAndroid Build Coastguard Worker     vec2 destinationPosition =
372*38e8c45fSAndroid Build Coastguard Worker             calculateDestinationPosition(destinationViewport, cursorOffset - destinationOffset,
373*38e8c45fSAndroid Build Coastguard Worker                                          sourceBoundary);
374*38e8c45fSAndroid Build Coastguard Worker 
375*38e8c45fSAndroid Build Coastguard Worker     // Transform position back to un-rotated coordinate space before sending it to controller
376*38e8c45fSAndroid Build Coastguard Worker     destinationPosition = pc.getDisplayTransform().inverse().transform(destinationPosition.x,
377*38e8c45fSAndroid Build Coastguard Worker                                                                        destinationPosition.y);
378*38e8c45fSAndroid Build Coastguard Worker     pc.setPosition(destinationPosition.x, destinationPosition.y);
379*38e8c45fSAndroid Build Coastguard Worker     pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
380*38e8c45fSAndroid Build Coastguard Worker }
381*38e8c45fSAndroid Build Coastguard Worker 
calculateDestinationPosition(const DisplayViewport & destinationViewport,float pointerOffset,DisplayPosition sourceBoundary)382*38e8c45fSAndroid Build Coastguard Worker vec2 PointerChoreographer::calculateDestinationPosition(const DisplayViewport& destinationViewport,
383*38e8c45fSAndroid Build Coastguard Worker                                                         float pointerOffset,
384*38e8c45fSAndroid Build Coastguard Worker                                                         DisplayPosition sourceBoundary) {
385*38e8c45fSAndroid Build Coastguard Worker     // destination is opposite of the source boundary
386*38e8c45fSAndroid Build Coastguard Worker     switch (sourceBoundary) {
387*38e8c45fSAndroid Build Coastguard Worker         case DisplayPosition::RIGHT:
388*38e8c45fSAndroid Build Coastguard Worker             return {0, pointerOffset}; // left edge
389*38e8c45fSAndroid Build Coastguard Worker         case DisplayPosition::TOP:
390*38e8c45fSAndroid Build Coastguard Worker             return {pointerOffset, destinationViewport.logicalBottom}; // bottom edge
391*38e8c45fSAndroid Build Coastguard Worker         case DisplayPosition::LEFT:
392*38e8c45fSAndroid Build Coastguard Worker             return {destinationViewport.logicalRight, pointerOffset}; // right edge
393*38e8c45fSAndroid Build Coastguard Worker         case DisplayPosition::BOTTOM:
394*38e8c45fSAndroid Build Coastguard Worker             return {pointerOffset, 0}; // top edge
395*38e8c45fSAndroid Build Coastguard Worker     }
396*38e8c45fSAndroid Build Coastguard Worker }
397*38e8c45fSAndroid Build Coastguard Worker 
processDrawingTabletEventLocked(const android::NotifyMotionArgs & args)398*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) {
399*38e8c45fSAndroid Build Coastguard Worker     if (args.displayId == ui::LogicalDisplayId::INVALID) {
400*38e8c45fSAndroid Build Coastguard Worker         return;
401*38e8c45fSAndroid Build Coastguard Worker     }
402*38e8c45fSAndroid Build Coastguard Worker 
403*38e8c45fSAndroid Build Coastguard Worker     if (args.getPointerCount() != 1) {
404*38e8c45fSAndroid Build Coastguard Worker         LOG(WARNING) << "Only drawing tablet events with a single pointer are currently supported: "
405*38e8c45fSAndroid Build Coastguard Worker                      << args.dump();
406*38e8c45fSAndroid Build Coastguard Worker     }
407*38e8c45fSAndroid Build Coastguard Worker 
408*38e8c45fSAndroid Build Coastguard Worker     // Use a mouse pointer controller for drawing tablets, or create one if it doesn't exist.
409*38e8c45fSAndroid Build Coastguard Worker     auto [it, controllerAdded] =
410*38e8c45fSAndroid Build Coastguard Worker             mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
411*38e8c45fSAndroid Build Coastguard Worker                                                        getMouseControllerConstructor(
412*38e8c45fSAndroid Build Coastguard Worker                                                                args.displayId));
413*38e8c45fSAndroid Build Coastguard Worker     if (controllerAdded) {
414*38e8c45fSAndroid Build Coastguard Worker         onControllerAddedOrRemovedLocked();
415*38e8c45fSAndroid Build Coastguard Worker     }
416*38e8c45fSAndroid Build Coastguard Worker 
417*38e8c45fSAndroid Build Coastguard Worker     PointerControllerInterface& pc = *it->second;
418*38e8c45fSAndroid Build Coastguard Worker 
419*38e8c45fSAndroid Build Coastguard Worker     const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
420*38e8c45fSAndroid Build Coastguard Worker     const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
421*38e8c45fSAndroid Build Coastguard Worker     pc.setPosition(x, y);
422*38e8c45fSAndroid Build Coastguard Worker     if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
423*38e8c45fSAndroid Build Coastguard Worker         // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
424*38e8c45fSAndroid Build Coastguard Worker         //   immediately by a DOWN event.
425*38e8c45fSAndroid Build Coastguard Worker         pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
426*38e8c45fSAndroid Build Coastguard Worker         pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
427*38e8c45fSAndroid Build Coastguard Worker     } else if (canUnfadeOnDisplay(args.displayId)) {
428*38e8c45fSAndroid Build Coastguard Worker         pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
429*38e8c45fSAndroid Build Coastguard Worker     }
430*38e8c45fSAndroid Build Coastguard Worker }
431*38e8c45fSAndroid Build Coastguard Worker 
432*38e8c45fSAndroid Build Coastguard Worker /**
433*38e8c45fSAndroid Build Coastguard Worker  * When screen is touched, fade the mouse pointer on that display. We only call fade for
434*38e8c45fSAndroid Build Coastguard Worker  * ACTION_DOWN events.This would allow both mouse and touch to be used at the same time if the
435*38e8c45fSAndroid Build Coastguard Worker  * mouse device keeps moving and unfades the cursor.
436*38e8c45fSAndroid Build Coastguard Worker  * For touch events, we do not need to populate the cursor position.
437*38e8c45fSAndroid Build Coastguard Worker  */
processTouchscreenAndStylusEventLocked(const NotifyMotionArgs & args)438*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) {
439*38e8c45fSAndroid Build Coastguard Worker     if (!args.displayId.isValid()) {
440*38e8c45fSAndroid Build Coastguard Worker         return;
441*38e8c45fSAndroid Build Coastguard Worker     }
442*38e8c45fSAndroid Build Coastguard Worker 
443*38e8c45fSAndroid Build Coastguard Worker     if (const auto it = mMousePointersByDisplay.find(args.displayId);
444*38e8c45fSAndroid Build Coastguard Worker         it != mMousePointersByDisplay.end() && args.action == AMOTION_EVENT_ACTION_DOWN) {
445*38e8c45fSAndroid Build Coastguard Worker         it->second->fade(PointerControllerInterface::Transition::GRADUAL);
446*38e8c45fSAndroid Build Coastguard Worker     }
447*38e8c45fSAndroid Build Coastguard Worker 
448*38e8c45fSAndroid Build Coastguard Worker     if (!mShowTouchesEnabled) {
449*38e8c45fSAndroid Build Coastguard Worker         return;
450*38e8c45fSAndroid Build Coastguard Worker     }
451*38e8c45fSAndroid Build Coastguard Worker 
452*38e8c45fSAndroid Build Coastguard Worker     // Get the touch pointer controller for the device, or create one if it doesn't exist.
453*38e8c45fSAndroid Build Coastguard Worker     auto [it, controllerAdded] =
454*38e8c45fSAndroid Build Coastguard Worker             mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
455*38e8c45fSAndroid Build Coastguard Worker     if (controllerAdded) {
456*38e8c45fSAndroid Build Coastguard Worker         onControllerAddedOrRemovedLocked();
457*38e8c45fSAndroid Build Coastguard Worker     }
458*38e8c45fSAndroid Build Coastguard Worker 
459*38e8c45fSAndroid Build Coastguard Worker     PointerControllerInterface& pc = *it->second;
460*38e8c45fSAndroid Build Coastguard Worker 
461*38e8c45fSAndroid Build Coastguard Worker     const PointerCoords* coords = args.pointerCoords.data();
462*38e8c45fSAndroid Build Coastguard Worker     const int32_t maskedAction = MotionEvent::getActionMasked(args.action);
463*38e8c45fSAndroid Build Coastguard Worker     const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
464*38e8c45fSAndroid Build Coastguard Worker     std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
465*38e8c45fSAndroid Build Coastguard Worker     BitSet32 idBits;
466*38e8c45fSAndroid Build Coastguard Worker     if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL &&
467*38e8c45fSAndroid Build Coastguard Worker         maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) {
468*38e8c45fSAndroid Build Coastguard Worker         for (size_t i = 0; i < args.getPointerCount(); i++) {
469*38e8c45fSAndroid Build Coastguard Worker             if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
470*38e8c45fSAndroid Build Coastguard Worker                 continue;
471*38e8c45fSAndroid Build Coastguard Worker             }
472*38e8c45fSAndroid Build Coastguard Worker             uint32_t id = args.pointerProperties[i].id;
473*38e8c45fSAndroid Build Coastguard Worker             idToIndex[id] = i;
474*38e8c45fSAndroid Build Coastguard Worker             idBits.markBit(id);
475*38e8c45fSAndroid Build Coastguard Worker         }
476*38e8c45fSAndroid Build Coastguard Worker     }
477*38e8c45fSAndroid Build Coastguard Worker     // The PointerController already handles setting spots per-display, so
478*38e8c45fSAndroid Build Coastguard Worker     // we do not need to manually manage display changes for touch spots for now.
479*38e8c45fSAndroid Build Coastguard Worker     pc.setSpots(coords, idToIndex.cbegin(), idBits, args.displayId);
480*38e8c45fSAndroid Build Coastguard Worker }
481*38e8c45fSAndroid Build Coastguard Worker 
processStylusHoverEventLocked(const NotifyMotionArgs & args)482*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::processStylusHoverEventLocked(const NotifyMotionArgs& args) {
483*38e8c45fSAndroid Build Coastguard Worker     if (!args.displayId.isValid()) {
484*38e8c45fSAndroid Build Coastguard Worker         return;
485*38e8c45fSAndroid Build Coastguard Worker     }
486*38e8c45fSAndroid Build Coastguard Worker 
487*38e8c45fSAndroid Build Coastguard Worker     if (args.getPointerCount() != 1) {
488*38e8c45fSAndroid Build Coastguard Worker         LOG(WARNING) << "Only stylus hover events with a single pointer are currently supported: "
489*38e8c45fSAndroid Build Coastguard Worker                      << args.dump();
490*38e8c45fSAndroid Build Coastguard Worker     }
491*38e8c45fSAndroid Build Coastguard Worker 
492*38e8c45fSAndroid Build Coastguard Worker     // Get the stylus pointer controller for the device, or create one if it doesn't exist.
493*38e8c45fSAndroid Build Coastguard Worker     auto [it, controllerAdded] =
494*38e8c45fSAndroid Build Coastguard Worker             mStylusPointersByDevice.try_emplace(args.deviceId,
495*38e8c45fSAndroid Build Coastguard Worker                                                 getStylusControllerConstructor(args.displayId));
496*38e8c45fSAndroid Build Coastguard Worker     if (controllerAdded) {
497*38e8c45fSAndroid Build Coastguard Worker         onControllerAddedOrRemovedLocked();
498*38e8c45fSAndroid Build Coastguard Worker     }
499*38e8c45fSAndroid Build Coastguard Worker 
500*38e8c45fSAndroid Build Coastguard Worker     PointerControllerInterface& pc = *it->second;
501*38e8c45fSAndroid Build Coastguard Worker 
502*38e8c45fSAndroid Build Coastguard Worker     const float x = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
503*38e8c45fSAndroid Build Coastguard Worker     const float y = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
504*38e8c45fSAndroid Build Coastguard Worker     pc.setPosition(x, y);
505*38e8c45fSAndroid Build Coastguard Worker     if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
506*38e8c45fSAndroid Build Coastguard Worker         // TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
507*38e8c45fSAndroid Build Coastguard Worker         //   immediately by a DOWN event.
508*38e8c45fSAndroid Build Coastguard Worker         pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
509*38e8c45fSAndroid Build Coastguard Worker         pc.updatePointerIcon(mShowTouchesEnabled ? PointerIconStyle::TYPE_SPOT_HOVER
510*38e8c45fSAndroid Build Coastguard Worker                                                  : PointerIconStyle::TYPE_NOT_SPECIFIED);
511*38e8c45fSAndroid Build Coastguard Worker     } else if (canUnfadeOnDisplay(args.displayId)) {
512*38e8c45fSAndroid Build Coastguard Worker         pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
513*38e8c45fSAndroid Build Coastguard Worker     }
514*38e8c45fSAndroid Build Coastguard Worker }
515*38e8c45fSAndroid Build Coastguard Worker 
notifySwitch(const NotifySwitchArgs & args)516*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::notifySwitch(const NotifySwitchArgs& args) {
517*38e8c45fSAndroid Build Coastguard Worker     mNextListener.notify(args);
518*38e8c45fSAndroid Build Coastguard Worker }
519*38e8c45fSAndroid Build Coastguard Worker 
notifySensor(const NotifySensorArgs & args)520*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::notifySensor(const NotifySensorArgs& args) {
521*38e8c45fSAndroid Build Coastguard Worker     mNextListener.notify(args);
522*38e8c45fSAndroid Build Coastguard Worker }
523*38e8c45fSAndroid Build Coastguard Worker 
notifyVibratorState(const NotifyVibratorStateArgs & args)524*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::notifyVibratorState(const NotifyVibratorStateArgs& args) {
525*38e8c45fSAndroid Build Coastguard Worker     mNextListener.notify(args);
526*38e8c45fSAndroid Build Coastguard Worker }
527*38e8c45fSAndroid Build Coastguard Worker 
notifyDeviceReset(const NotifyDeviceResetArgs & args)528*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
529*38e8c45fSAndroid Build Coastguard Worker     processDeviceReset(args);
530*38e8c45fSAndroid Build Coastguard Worker 
531*38e8c45fSAndroid Build Coastguard Worker     mNextListener.notify(args);
532*38e8c45fSAndroid Build Coastguard Worker }
533*38e8c45fSAndroid Build Coastguard Worker 
processDeviceReset(const NotifyDeviceResetArgs & args)534*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) {
535*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(getLock());
536*38e8c45fSAndroid Build Coastguard Worker     mTouchPointersByDevice.erase(args.deviceId);
537*38e8c45fSAndroid Build Coastguard Worker     mStylusPointersByDevice.erase(args.deviceId);
538*38e8c45fSAndroid Build Coastguard Worker     mDrawingTabletPointersByDevice.erase(args.deviceId);
539*38e8c45fSAndroid Build Coastguard Worker     onControllerAddedOrRemovedLocked();
540*38e8c45fSAndroid Build Coastguard Worker }
541*38e8c45fSAndroid Build Coastguard Worker 
onControllerAddedOrRemovedLocked()542*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::onControllerAddedOrRemovedLocked() {
543*38e8c45fSAndroid Build Coastguard Worker     if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows() &&
544*38e8c45fSAndroid Build Coastguard Worker         !com::android::input::flags::connected_displays_cursor()) {
545*38e8c45fSAndroid Build Coastguard Worker         return;
546*38e8c45fSAndroid Build Coastguard Worker     }
547*38e8c45fSAndroid Build Coastguard Worker     bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() ||
548*38e8c45fSAndroid Build Coastguard Worker             !mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty();
549*38e8c45fSAndroid Build Coastguard Worker 
550*38e8c45fSAndroid Build Coastguard Worker     // PointerChoreographer uses Listener's lock which is already held by caller
551*38e8c45fSAndroid Build Coastguard Worker     base::ScopedLockAssertion assumeLocked(mWindowInfoListener->mLock);
552*38e8c45fSAndroid Build Coastguard Worker 
553*38e8c45fSAndroid Build Coastguard Worker     if (requireListener && !mIsWindowInfoListenerRegistered) {
554*38e8c45fSAndroid Build Coastguard Worker         mIsWindowInfoListenerRegistered = true;
555*38e8c45fSAndroid Build Coastguard Worker         mWindowInfoListener->setInitialDisplayInfosLocked(mRegisterListener(mWindowInfoListener));
556*38e8c45fSAndroid Build Coastguard Worker         onPrivacySensitiveDisplaysChangedLocked(
557*38e8c45fSAndroid Build Coastguard Worker                 mWindowInfoListener->getPrivacySensitiveDisplaysLocked());
558*38e8c45fSAndroid Build Coastguard Worker     } else if (!requireListener && mIsWindowInfoListenerRegistered) {
559*38e8c45fSAndroid Build Coastguard Worker         mIsWindowInfoListenerRegistered = false;
560*38e8c45fSAndroid Build Coastguard Worker         mUnregisterListener(mWindowInfoListener);
561*38e8c45fSAndroid Build Coastguard Worker     } else if (requireListener) {
562*38e8c45fSAndroid Build Coastguard Worker         // controller may have been added to an existing privacy sensitive display, we need to
563*38e8c45fSAndroid Build Coastguard Worker         // update all controllers again
564*38e8c45fSAndroid Build Coastguard Worker         onPrivacySensitiveDisplaysChangedLocked(
565*38e8c45fSAndroid Build Coastguard Worker                 mWindowInfoListener->getPrivacySensitiveDisplaysLocked());
566*38e8c45fSAndroid Build Coastguard Worker     }
567*38e8c45fSAndroid Build Coastguard Worker }
568*38e8c45fSAndroid Build Coastguard Worker 
onPrivacySensitiveDisplaysChangedLocked(const std::unordered_set<ui::LogicalDisplayId> & privacySensitiveDisplays)569*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::onPrivacySensitiveDisplaysChangedLocked(
570*38e8c45fSAndroid Build Coastguard Worker         const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) {
571*38e8c45fSAndroid Build Coastguard Worker     for (auto& [_, pc] : mTouchPointersByDevice) {
572*38e8c45fSAndroid Build Coastguard Worker         pc->clearSkipScreenshotFlags();
573*38e8c45fSAndroid Build Coastguard Worker         for (auto displayId : privacySensitiveDisplays) {
574*38e8c45fSAndroid Build Coastguard Worker             pc->setSkipScreenshotFlagForDisplay(displayId);
575*38e8c45fSAndroid Build Coastguard Worker         }
576*38e8c45fSAndroid Build Coastguard Worker     }
577*38e8c45fSAndroid Build Coastguard Worker 
578*38e8c45fSAndroid Build Coastguard Worker     for (auto& [displayId, pc] : mMousePointersByDisplay) {
579*38e8c45fSAndroid Build Coastguard Worker         if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
580*38e8c45fSAndroid Build Coastguard Worker             pc->setSkipScreenshotFlagForDisplay(displayId);
581*38e8c45fSAndroid Build Coastguard Worker         } else {
582*38e8c45fSAndroid Build Coastguard Worker             pc->clearSkipScreenshotFlags();
583*38e8c45fSAndroid Build Coastguard Worker         }
584*38e8c45fSAndroid Build Coastguard Worker     }
585*38e8c45fSAndroid Build Coastguard Worker 
586*38e8c45fSAndroid Build Coastguard Worker     for (auto* pointerControllerByDevice :
587*38e8c45fSAndroid Build Coastguard Worker          {&mDrawingTabletPointersByDevice, &mStylusPointersByDevice}) {
588*38e8c45fSAndroid Build Coastguard Worker         for (auto& [_, pc] : *pointerControllerByDevice) {
589*38e8c45fSAndroid Build Coastguard Worker             auto displayId = pc->getDisplayId();
590*38e8c45fSAndroid Build Coastguard Worker             if (privacySensitiveDisplays.find(displayId) != privacySensitiveDisplays.end()) {
591*38e8c45fSAndroid Build Coastguard Worker                 pc->setSkipScreenshotFlagForDisplay(displayId);
592*38e8c45fSAndroid Build Coastguard Worker             } else {
593*38e8c45fSAndroid Build Coastguard Worker                 pc->clearSkipScreenshotFlags();
594*38e8c45fSAndroid Build Coastguard Worker             }
595*38e8c45fSAndroid Build Coastguard Worker         }
596*38e8c45fSAndroid Build Coastguard Worker     }
597*38e8c45fSAndroid Build Coastguard Worker }
598*38e8c45fSAndroid Build Coastguard Worker 
notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs & args)599*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::notifyPointerCaptureChanged(
600*38e8c45fSAndroid Build Coastguard Worker         const NotifyPointerCaptureChangedArgs& args) {
601*38e8c45fSAndroid Build Coastguard Worker     if (args.request.isEnable()) {
602*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(getLock());
603*38e8c45fSAndroid Build Coastguard Worker         for (const auto& [_, mousePointerController] : mMousePointersByDisplay) {
604*38e8c45fSAndroid Build Coastguard Worker             mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
605*38e8c45fSAndroid Build Coastguard Worker         }
606*38e8c45fSAndroid Build Coastguard Worker     }
607*38e8c45fSAndroid Build Coastguard Worker     mNextListener.notify(args);
608*38e8c45fSAndroid Build Coastguard Worker }
609*38e8c45fSAndroid Build Coastguard Worker 
setDisplayTopology(const std::unordered_map<ui::LogicalDisplayId,std::vector<AdjacentDisplay>> & displayTopology)610*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::setDisplayTopology(
611*38e8c45fSAndroid Build Coastguard Worker         const std::unordered_map<ui::LogicalDisplayId, std::vector<AdjacentDisplay>>&
612*38e8c45fSAndroid Build Coastguard Worker                 displayTopology) {
613*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(getLock());
614*38e8c45fSAndroid Build Coastguard Worker     mTopology = displayTopology;
615*38e8c45fSAndroid Build Coastguard Worker }
616*38e8c45fSAndroid Build Coastguard Worker 
dump(std::string & dump)617*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::dump(std::string& dump) {
618*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(getLock());
619*38e8c45fSAndroid Build Coastguard Worker 
620*38e8c45fSAndroid Build Coastguard Worker     dump += "PointerChoreographer:\n";
621*38e8c45fSAndroid Build Coastguard Worker     dump += StringPrintf(INDENT "Show Touches Enabled: %s\n",
622*38e8c45fSAndroid Build Coastguard Worker                          mShowTouchesEnabled ? "true" : "false");
623*38e8c45fSAndroid Build Coastguard Worker     dump += StringPrintf(INDENT "Stylus PointerIcon Enabled: %s\n",
624*38e8c45fSAndroid Build Coastguard Worker                          mStylusPointerIconEnabled ? "true" : "false");
625*38e8c45fSAndroid Build Coastguard Worker 
626*38e8c45fSAndroid Build Coastguard Worker     dump += INDENT "MousePointerControllers:\n";
627*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [displayId, mousePointerController] : mMousePointersByDisplay) {
628*38e8c45fSAndroid Build Coastguard Worker         std::string pointerControllerDump = addLinePrefix(mousePointerController->dump(), INDENT);
629*38e8c45fSAndroid Build Coastguard Worker         dump += INDENT + displayId.toString() + " : " + pointerControllerDump;
630*38e8c45fSAndroid Build Coastguard Worker     }
631*38e8c45fSAndroid Build Coastguard Worker     dump += INDENT "TouchPointerControllers:\n";
632*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [deviceId, touchPointerController] : mTouchPointersByDevice) {
633*38e8c45fSAndroid Build Coastguard Worker         std::string pointerControllerDump = addLinePrefix(touchPointerController->dump(), INDENT);
634*38e8c45fSAndroid Build Coastguard Worker         dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
635*38e8c45fSAndroid Build Coastguard Worker     }
636*38e8c45fSAndroid Build Coastguard Worker     dump += INDENT "StylusPointerControllers:\n";
637*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
638*38e8c45fSAndroid Build Coastguard Worker         std::string pointerControllerDump = addLinePrefix(stylusPointerController->dump(), INDENT);
639*38e8c45fSAndroid Build Coastguard Worker         dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
640*38e8c45fSAndroid Build Coastguard Worker     }
641*38e8c45fSAndroid Build Coastguard Worker     dump += INDENT "DrawingTabletControllers:\n";
642*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
643*38e8c45fSAndroid Build Coastguard Worker         std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT);
644*38e8c45fSAndroid Build Coastguard Worker         dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
645*38e8c45fSAndroid Build Coastguard Worker     }
646*38e8c45fSAndroid Build Coastguard Worker     dump += "\n";
647*38e8c45fSAndroid Build Coastguard Worker }
648*38e8c45fSAndroid Build Coastguard Worker 
findViewportByIdLocked(ui::LogicalDisplayId displayId) const649*38e8c45fSAndroid Build Coastguard Worker const DisplayViewport* PointerChoreographer::findViewportByIdLocked(
650*38e8c45fSAndroid Build Coastguard Worker         ui::LogicalDisplayId displayId) const {
651*38e8c45fSAndroid Build Coastguard Worker     for (auto& viewport : mViewports) {
652*38e8c45fSAndroid Build Coastguard Worker         if (viewport.displayId == displayId) {
653*38e8c45fSAndroid Build Coastguard Worker             return &viewport;
654*38e8c45fSAndroid Build Coastguard Worker         }
655*38e8c45fSAndroid Build Coastguard Worker     }
656*38e8c45fSAndroid Build Coastguard Worker     return nullptr;
657*38e8c45fSAndroid Build Coastguard Worker }
658*38e8c45fSAndroid Build Coastguard Worker 
getTargetMouseDisplayLocked(ui::LogicalDisplayId associatedDisplayId) const659*38e8c45fSAndroid Build Coastguard Worker ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked(
660*38e8c45fSAndroid Build Coastguard Worker         ui::LogicalDisplayId associatedDisplayId) const {
661*38e8c45fSAndroid Build Coastguard Worker     return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId;
662*38e8c45fSAndroid Build Coastguard Worker }
663*38e8c45fSAndroid Build Coastguard Worker 
664*38e8c45fSAndroid Build Coastguard Worker std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId)665*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) {
666*38e8c45fSAndroid Build Coastguard Worker     const ui::LogicalDisplayId displayId = getTargetMouseDisplayLocked(associatedDisplayId);
667*38e8c45fSAndroid Build Coastguard Worker 
668*38e8c45fSAndroid Build Coastguard Worker     auto it = mMousePointersByDisplay.find(displayId);
669*38e8c45fSAndroid Build Coastguard Worker     if (it == mMousePointersByDisplay.end()) {
670*38e8c45fSAndroid Build Coastguard Worker         it = mMousePointersByDisplay.emplace(displayId, getMouseControllerConstructor(displayId))
671*38e8c45fSAndroid Build Coastguard Worker                      .first;
672*38e8c45fSAndroid Build Coastguard Worker         onControllerAddedOrRemovedLocked();
673*38e8c45fSAndroid Build Coastguard Worker     }
674*38e8c45fSAndroid Build Coastguard Worker 
675*38e8c45fSAndroid Build Coastguard Worker     return {displayId, *it->second};
676*38e8c45fSAndroid Build Coastguard Worker }
677*38e8c45fSAndroid Build Coastguard Worker 
findInputDeviceLocked(DeviceId deviceId)678*38e8c45fSAndroid Build Coastguard Worker InputDeviceInfo* PointerChoreographer::findInputDeviceLocked(DeviceId deviceId) {
679*38e8c45fSAndroid Build Coastguard Worker     auto it = std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
680*38e8c45fSAndroid Build Coastguard Worker                            [deviceId](const auto& info) { return info.getId() == deviceId; });
681*38e8c45fSAndroid Build Coastguard Worker     return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
682*38e8c45fSAndroid Build Coastguard Worker }
683*38e8c45fSAndroid Build Coastguard Worker 
canUnfadeOnDisplay(ui::LogicalDisplayId displayId)684*38e8c45fSAndroid Build Coastguard Worker bool PointerChoreographer::canUnfadeOnDisplay(ui::LogicalDisplayId displayId) {
685*38e8c45fSAndroid Build Coastguard Worker     return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
686*38e8c45fSAndroid Build Coastguard Worker }
687*38e8c45fSAndroid Build Coastguard Worker 
getLock() const688*38e8c45fSAndroid Build Coastguard Worker std::mutex& PointerChoreographer::getLock() const {
689*38e8c45fSAndroid Build Coastguard Worker     return mWindowInfoListener->mLock;
690*38e8c45fSAndroid Build Coastguard Worker }
691*38e8c45fSAndroid Build Coastguard Worker 
updatePointerControllersLocked()692*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() {
693*38e8c45fSAndroid Build Coastguard Worker     std::set<ui::LogicalDisplayId /*displayId*/> mouseDisplaysToKeep;
694*38e8c45fSAndroid Build Coastguard Worker     std::set<DeviceId> touchDevicesToKeep;
695*38e8c45fSAndroid Build Coastguard Worker     std::set<DeviceId> stylusDevicesToKeep;
696*38e8c45fSAndroid Build Coastguard Worker     std::set<DeviceId> drawingTabletDevicesToKeep;
697*38e8c45fSAndroid Build Coastguard Worker 
698*38e8c45fSAndroid Build Coastguard Worker     // Mark the displayIds or deviceIds of PointerControllers currently needed, and create
699*38e8c45fSAndroid Build Coastguard Worker     // new PointerControllers if necessary.
700*38e8c45fSAndroid Build Coastguard Worker     for (const auto& info : mInputDeviceInfos) {
701*38e8c45fSAndroid Build Coastguard Worker         if (!info.isEnabled()) {
702*38e8c45fSAndroid Build Coastguard Worker             // If device is disabled, we should not keep it, and should not show pointer for
703*38e8c45fSAndroid Build Coastguard Worker             // disabled mouse device.
704*38e8c45fSAndroid Build Coastguard Worker             continue;
705*38e8c45fSAndroid Build Coastguard Worker         }
706*38e8c45fSAndroid Build Coastguard Worker         const uint32_t sources = info.getSources();
707*38e8c45fSAndroid Build Coastguard Worker         const bool isKnownMouse = mMouseDevices.count(info.getId()) != 0;
708*38e8c45fSAndroid Build Coastguard Worker 
709*38e8c45fSAndroid Build Coastguard Worker         if (isMouseOrTouchpad(sources) || isKnownMouse) {
710*38e8c45fSAndroid Build Coastguard Worker             const ui::LogicalDisplayId displayId =
711*38e8c45fSAndroid Build Coastguard Worker                     getTargetMouseDisplayLocked(info.getAssociatedDisplayId());
712*38e8c45fSAndroid Build Coastguard Worker             mouseDisplaysToKeep.insert(displayId);
713*38e8c45fSAndroid Build Coastguard Worker             // For mice, show the cursor immediately when the device is first connected or
714*38e8c45fSAndroid Build Coastguard Worker             // when it moves to a new display.
715*38e8c45fSAndroid Build Coastguard Worker             auto [mousePointerIt, isNewMousePointer] =
716*38e8c45fSAndroid Build Coastguard Worker                     mMousePointersByDisplay.try_emplace(displayId,
717*38e8c45fSAndroid Build Coastguard Worker                                                         getMouseControllerConstructor(displayId));
718*38e8c45fSAndroid Build Coastguard Worker             if (isNewMousePointer) {
719*38e8c45fSAndroid Build Coastguard Worker                 onControllerAddedOrRemovedLocked();
720*38e8c45fSAndroid Build Coastguard Worker             }
721*38e8c45fSAndroid Build Coastguard Worker 
722*38e8c45fSAndroid Build Coastguard Worker             mMouseDevices.emplace(info.getId());
723*38e8c45fSAndroid Build Coastguard Worker             if ((!isKnownMouse || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
724*38e8c45fSAndroid Build Coastguard Worker                 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
725*38e8c45fSAndroid Build Coastguard Worker             }
726*38e8c45fSAndroid Build Coastguard Worker         }
727*38e8c45fSAndroid Build Coastguard Worker         if (isFromSource(sources, AINPUT_SOURCE_TOUCHSCREEN) && mShowTouchesEnabled &&
728*38e8c45fSAndroid Build Coastguard Worker             info.getAssociatedDisplayId().isValid()) {
729*38e8c45fSAndroid Build Coastguard Worker             touchDevicesToKeep.insert(info.getId());
730*38e8c45fSAndroid Build Coastguard Worker         }
731*38e8c45fSAndroid Build Coastguard Worker         if (isFromSource(sources, AINPUT_SOURCE_STYLUS) && mStylusPointerIconEnabled &&
732*38e8c45fSAndroid Build Coastguard Worker             info.getAssociatedDisplayId().isValid()) {
733*38e8c45fSAndroid Build Coastguard Worker             stylusDevicesToKeep.insert(info.getId());
734*38e8c45fSAndroid Build Coastguard Worker         }
735*38e8c45fSAndroid Build Coastguard Worker         if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE) &&
736*38e8c45fSAndroid Build Coastguard Worker             info.getAssociatedDisplayId().isValid()) {
737*38e8c45fSAndroid Build Coastguard Worker             drawingTabletDevicesToKeep.insert(info.getId());
738*38e8c45fSAndroid Build Coastguard Worker         }
739*38e8c45fSAndroid Build Coastguard Worker     }
740*38e8c45fSAndroid Build Coastguard Worker 
741*38e8c45fSAndroid Build Coastguard Worker     // Remove PointerControllers no longer needed.
742*38e8c45fSAndroid Build Coastguard Worker     std::erase_if(mMousePointersByDisplay, [&mouseDisplaysToKeep](const auto& pair) {
743*38e8c45fSAndroid Build Coastguard Worker         return mouseDisplaysToKeep.find(pair.first) == mouseDisplaysToKeep.end();
744*38e8c45fSAndroid Build Coastguard Worker     });
745*38e8c45fSAndroid Build Coastguard Worker     std::erase_if(mTouchPointersByDevice, [&touchDevicesToKeep](const auto& pair) {
746*38e8c45fSAndroid Build Coastguard Worker         return touchDevicesToKeep.find(pair.first) == touchDevicesToKeep.end();
747*38e8c45fSAndroid Build Coastguard Worker     });
748*38e8c45fSAndroid Build Coastguard Worker     std::erase_if(mStylusPointersByDevice, [&stylusDevicesToKeep](const auto& pair) {
749*38e8c45fSAndroid Build Coastguard Worker         return stylusDevicesToKeep.find(pair.first) == stylusDevicesToKeep.end();
750*38e8c45fSAndroid Build Coastguard Worker     });
751*38e8c45fSAndroid Build Coastguard Worker     std::erase_if(mDrawingTabletPointersByDevice, [&drawingTabletDevicesToKeep](const auto& pair) {
752*38e8c45fSAndroid Build Coastguard Worker         return drawingTabletDevicesToKeep.find(pair.first) == drawingTabletDevicesToKeep.end();
753*38e8c45fSAndroid Build Coastguard Worker     });
754*38e8c45fSAndroid Build Coastguard Worker     std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(getLock()) {
755*38e8c45fSAndroid Build Coastguard Worker         return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(),
756*38e8c45fSAndroid Build Coastguard Worker                             [id](const auto& info) { return info.getId() == id; }) ==
757*38e8c45fSAndroid Build Coastguard Worker                 mInputDeviceInfos.end();
758*38e8c45fSAndroid Build Coastguard Worker     });
759*38e8c45fSAndroid Build Coastguard Worker 
760*38e8c45fSAndroid Build Coastguard Worker     onControllerAddedOrRemovedLocked();
761*38e8c45fSAndroid Build Coastguard Worker 
762*38e8c45fSAndroid Build Coastguard Worker     // Check if we need to notify the policy if there's a change on the pointer display ID.
763*38e8c45fSAndroid Build Coastguard Worker     return calculatePointerDisplayChangeToNotify();
764*38e8c45fSAndroid Build Coastguard Worker }
765*38e8c45fSAndroid Build Coastguard Worker 
766*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::PointerDisplayChange
calculatePointerDisplayChangeToNotify()767*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::calculatePointerDisplayChangeToNotify() {
768*38e8c45fSAndroid Build Coastguard Worker     ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
769*38e8c45fSAndroid Build Coastguard Worker     vec2 cursorPosition = {0, 0};
770*38e8c45fSAndroid Build Coastguard Worker     if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
771*38e8c45fSAndroid Build Coastguard Worker         it != mMousePointersByDisplay.end()) {
772*38e8c45fSAndroid Build Coastguard Worker         const auto& pointerController = it->second;
773*38e8c45fSAndroid Build Coastguard Worker         // Use the displayId from the pointerController, because it accurately reflects whether
774*38e8c45fSAndroid Build Coastguard Worker         // the viewport has been added for that display. Otherwise, we would have to check if
775*38e8c45fSAndroid Build Coastguard Worker         // the viewport exists separately.
776*38e8c45fSAndroid Build Coastguard Worker         displayIdToNotify = pointerController->getDisplayId();
777*38e8c45fSAndroid Build Coastguard Worker         cursorPosition = pointerController->getPosition();
778*38e8c45fSAndroid Build Coastguard Worker     }
779*38e8c45fSAndroid Build Coastguard Worker     if (mNotifiedPointerDisplayId == displayIdToNotify) {
780*38e8c45fSAndroid Build Coastguard Worker         return {};
781*38e8c45fSAndroid Build Coastguard Worker     }
782*38e8c45fSAndroid Build Coastguard Worker     mNotifiedPointerDisplayId = displayIdToNotify;
783*38e8c45fSAndroid Build Coastguard Worker     return {{displayIdToNotify, cursorPosition}};
784*38e8c45fSAndroid Build Coastguard Worker }
785*38e8c45fSAndroid Build Coastguard Worker 
setDefaultMouseDisplayId(ui::LogicalDisplayId displayId)786*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
787*38e8c45fSAndroid Build Coastguard Worker     PointerDisplayChange pointerDisplayChange;
788*38e8c45fSAndroid Build Coastguard Worker 
789*38e8c45fSAndroid Build Coastguard Worker     { // acquire lock
790*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(getLock());
791*38e8c45fSAndroid Build Coastguard Worker 
792*38e8c45fSAndroid Build Coastguard Worker         mDefaultMouseDisplayId = displayId;
793*38e8c45fSAndroid Build Coastguard Worker         pointerDisplayChange = updatePointerControllersLocked();
794*38e8c45fSAndroid Build Coastguard Worker     } // release lock
795*38e8c45fSAndroid Build Coastguard Worker 
796*38e8c45fSAndroid Build Coastguard Worker     notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
797*38e8c45fSAndroid Build Coastguard Worker }
798*38e8c45fSAndroid Build Coastguard Worker 
setDisplayViewports(const std::vector<DisplayViewport> & viewports)799*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
800*38e8c45fSAndroid Build Coastguard Worker     PointerDisplayChange pointerDisplayChange;
801*38e8c45fSAndroid Build Coastguard Worker 
802*38e8c45fSAndroid Build Coastguard Worker     { // acquire lock
803*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(getLock());
804*38e8c45fSAndroid Build Coastguard Worker         for (const auto& viewport : viewports) {
805*38e8c45fSAndroid Build Coastguard Worker             const ui::LogicalDisplayId displayId = viewport.displayId;
806*38e8c45fSAndroid Build Coastguard Worker             if (const auto it = mMousePointersByDisplay.find(displayId);
807*38e8c45fSAndroid Build Coastguard Worker                 it != mMousePointersByDisplay.end()) {
808*38e8c45fSAndroid Build Coastguard Worker                 it->second->setDisplayViewport(viewport);
809*38e8c45fSAndroid Build Coastguard Worker             }
810*38e8c45fSAndroid Build Coastguard Worker             for (const auto& [deviceId, stylusPointerController] : mStylusPointersByDevice) {
811*38e8c45fSAndroid Build Coastguard Worker                 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
812*38e8c45fSAndroid Build Coastguard Worker                 if (info && info->getAssociatedDisplayId() == displayId) {
813*38e8c45fSAndroid Build Coastguard Worker                     stylusPointerController->setDisplayViewport(viewport);
814*38e8c45fSAndroid Build Coastguard Worker                 }
815*38e8c45fSAndroid Build Coastguard Worker             }
816*38e8c45fSAndroid Build Coastguard Worker             for (const auto& [deviceId, drawingTabletController] : mDrawingTabletPointersByDevice) {
817*38e8c45fSAndroid Build Coastguard Worker                 const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
818*38e8c45fSAndroid Build Coastguard Worker                 if (info && info->getAssociatedDisplayId() == displayId) {
819*38e8c45fSAndroid Build Coastguard Worker                     drawingTabletController->setDisplayViewport(viewport);
820*38e8c45fSAndroid Build Coastguard Worker                 }
821*38e8c45fSAndroid Build Coastguard Worker             }
822*38e8c45fSAndroid Build Coastguard Worker         }
823*38e8c45fSAndroid Build Coastguard Worker         mViewports = viewports;
824*38e8c45fSAndroid Build Coastguard Worker         pointerDisplayChange = calculatePointerDisplayChangeToNotify();
825*38e8c45fSAndroid Build Coastguard Worker     } // release lock
826*38e8c45fSAndroid Build Coastguard Worker 
827*38e8c45fSAndroid Build Coastguard Worker     notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
828*38e8c45fSAndroid Build Coastguard Worker }
829*38e8c45fSAndroid Build Coastguard Worker 
getViewportForPointerDevice(ui::LogicalDisplayId associatedDisplayId)830*38e8c45fSAndroid Build Coastguard Worker std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice(
831*38e8c45fSAndroid Build Coastguard Worker         ui::LogicalDisplayId associatedDisplayId) {
832*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(getLock());
833*38e8c45fSAndroid Build Coastguard Worker     const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId);
834*38e8c45fSAndroid Build Coastguard Worker     if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) {
835*38e8c45fSAndroid Build Coastguard Worker         return *viewport;
836*38e8c45fSAndroid Build Coastguard Worker     }
837*38e8c45fSAndroid Build Coastguard Worker     return std::nullopt;
838*38e8c45fSAndroid Build Coastguard Worker }
839*38e8c45fSAndroid Build Coastguard Worker 
getMouseCursorPosition(ui::LogicalDisplayId displayId)840*38e8c45fSAndroid Build Coastguard Worker vec2 PointerChoreographer::getMouseCursorPosition(ui::LogicalDisplayId displayId) {
841*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(getLock());
842*38e8c45fSAndroid Build Coastguard Worker     const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(displayId);
843*38e8c45fSAndroid Build Coastguard Worker     if (auto it = mMousePointersByDisplay.find(resolvedDisplayId);
844*38e8c45fSAndroid Build Coastguard Worker         it != mMousePointersByDisplay.end()) {
845*38e8c45fSAndroid Build Coastguard Worker         return it->second->getPosition();
846*38e8c45fSAndroid Build Coastguard Worker     }
847*38e8c45fSAndroid Build Coastguard Worker     return {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION};
848*38e8c45fSAndroid Build Coastguard Worker }
849*38e8c45fSAndroid Build Coastguard Worker 
setShowTouchesEnabled(bool enabled)850*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::setShowTouchesEnabled(bool enabled) {
851*38e8c45fSAndroid Build Coastguard Worker     PointerDisplayChange pointerDisplayChange;
852*38e8c45fSAndroid Build Coastguard Worker 
853*38e8c45fSAndroid Build Coastguard Worker     { // acquire lock
854*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(getLock());
855*38e8c45fSAndroid Build Coastguard Worker         if (mShowTouchesEnabled == enabled) {
856*38e8c45fSAndroid Build Coastguard Worker             return;
857*38e8c45fSAndroid Build Coastguard Worker         }
858*38e8c45fSAndroid Build Coastguard Worker         mShowTouchesEnabled = enabled;
859*38e8c45fSAndroid Build Coastguard Worker         pointerDisplayChange = updatePointerControllersLocked();
860*38e8c45fSAndroid Build Coastguard Worker     } // release lock
861*38e8c45fSAndroid Build Coastguard Worker 
862*38e8c45fSAndroid Build Coastguard Worker     notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
863*38e8c45fSAndroid Build Coastguard Worker }
864*38e8c45fSAndroid Build Coastguard Worker 
setStylusPointerIconEnabled(bool enabled)865*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) {
866*38e8c45fSAndroid Build Coastguard Worker     PointerDisplayChange pointerDisplayChange;
867*38e8c45fSAndroid Build Coastguard Worker 
868*38e8c45fSAndroid Build Coastguard Worker     { // acquire lock
869*38e8c45fSAndroid Build Coastguard Worker         std::scoped_lock _l(getLock());
870*38e8c45fSAndroid Build Coastguard Worker         if (mStylusPointerIconEnabled == enabled) {
871*38e8c45fSAndroid Build Coastguard Worker             return;
872*38e8c45fSAndroid Build Coastguard Worker         }
873*38e8c45fSAndroid Build Coastguard Worker         mStylusPointerIconEnabled = enabled;
874*38e8c45fSAndroid Build Coastguard Worker         pointerDisplayChange = updatePointerControllersLocked();
875*38e8c45fSAndroid Build Coastguard Worker     } // release lock
876*38e8c45fSAndroid Build Coastguard Worker 
877*38e8c45fSAndroid Build Coastguard Worker     notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
878*38e8c45fSAndroid Build Coastguard Worker }
879*38e8c45fSAndroid Build Coastguard Worker 
setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>,PointerIconStyle> icon,ui::LogicalDisplayId displayId,DeviceId deviceId)880*38e8c45fSAndroid Build Coastguard Worker bool PointerChoreographer::setPointerIcon(
881*38e8c45fSAndroid Build Coastguard Worker         std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
882*38e8c45fSAndroid Build Coastguard Worker         ui::LogicalDisplayId displayId, DeviceId deviceId) {
883*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(getLock());
884*38e8c45fSAndroid Build Coastguard Worker     if (deviceId < 0) {
885*38e8c45fSAndroid Build Coastguard Worker         LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
886*38e8c45fSAndroid Build Coastguard Worker         return false;
887*38e8c45fSAndroid Build Coastguard Worker     }
888*38e8c45fSAndroid Build Coastguard Worker     const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
889*38e8c45fSAndroid Build Coastguard Worker     if (!info) {
890*38e8c45fSAndroid Build Coastguard Worker         LOG(WARNING) << "No input device info found for id " << deviceId
891*38e8c45fSAndroid Build Coastguard Worker                      << ". Cannot set pointer icon.";
892*38e8c45fSAndroid Build Coastguard Worker         return false;
893*38e8c45fSAndroid Build Coastguard Worker     }
894*38e8c45fSAndroid Build Coastguard Worker     const uint32_t sources = info->getSources();
895*38e8c45fSAndroid Build Coastguard Worker 
896*38e8c45fSAndroid Build Coastguard Worker     if (isFromSource(sources, AINPUT_SOURCE_STYLUS | AINPUT_SOURCE_MOUSE)) {
897*38e8c45fSAndroid Build Coastguard Worker         auto it = mDrawingTabletPointersByDevice.find(deviceId);
898*38e8c45fSAndroid Build Coastguard Worker         if (it != mDrawingTabletPointersByDevice.end()) {
899*38e8c45fSAndroid Build Coastguard Worker             setIconForController(icon, *it->second);
900*38e8c45fSAndroid Build Coastguard Worker             return true;
901*38e8c45fSAndroid Build Coastguard Worker         }
902*38e8c45fSAndroid Build Coastguard Worker     }
903*38e8c45fSAndroid Build Coastguard Worker     if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) {
904*38e8c45fSAndroid Build Coastguard Worker         auto it = mStylusPointersByDevice.find(deviceId);
905*38e8c45fSAndroid Build Coastguard Worker         if (it != mStylusPointersByDevice.end()) {
906*38e8c45fSAndroid Build Coastguard Worker             if (mShowTouchesEnabled) {
907*38e8c45fSAndroid Build Coastguard Worker                 // If an app doesn't override the icon for the hovering stylus, show the hover icon.
908*38e8c45fSAndroid Build Coastguard Worker                 auto* style = std::get_if<PointerIconStyle>(&icon);
909*38e8c45fSAndroid Build Coastguard Worker                 if (style != nullptr && *style == PointerIconStyle::TYPE_NOT_SPECIFIED) {
910*38e8c45fSAndroid Build Coastguard Worker                     *style = PointerIconStyle::TYPE_SPOT_HOVER;
911*38e8c45fSAndroid Build Coastguard Worker                 }
912*38e8c45fSAndroid Build Coastguard Worker             }
913*38e8c45fSAndroid Build Coastguard Worker             setIconForController(icon, *it->second);
914*38e8c45fSAndroid Build Coastguard Worker             return true;
915*38e8c45fSAndroid Build Coastguard Worker         }
916*38e8c45fSAndroid Build Coastguard Worker     }
917*38e8c45fSAndroid Build Coastguard Worker     if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
918*38e8c45fSAndroid Build Coastguard Worker         auto it = mMousePointersByDisplay.find(displayId);
919*38e8c45fSAndroid Build Coastguard Worker         if (it != mMousePointersByDisplay.end()) {
920*38e8c45fSAndroid Build Coastguard Worker             setIconForController(icon, *it->second);
921*38e8c45fSAndroid Build Coastguard Worker             return true;
922*38e8c45fSAndroid Build Coastguard Worker         } else {
923*38e8c45fSAndroid Build Coastguard Worker             LOG(WARNING) << "No mouse pointer controller found for display " << displayId
924*38e8c45fSAndroid Build Coastguard Worker                          << ", device " << deviceId << ".";
925*38e8c45fSAndroid Build Coastguard Worker             return false;
926*38e8c45fSAndroid Build Coastguard Worker         }
927*38e8c45fSAndroid Build Coastguard Worker     }
928*38e8c45fSAndroid Build Coastguard Worker     LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device " << deviceId
929*38e8c45fSAndroid Build Coastguard Worker                  << ".";
930*38e8c45fSAndroid Build Coastguard Worker     return false;
931*38e8c45fSAndroid Build Coastguard Worker }
932*38e8c45fSAndroid Build Coastguard Worker 
setPointerIconVisibility(ui::LogicalDisplayId displayId,bool visible)933*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) {
934*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(getLock());
935*38e8c45fSAndroid Build Coastguard Worker     if (visible) {
936*38e8c45fSAndroid Build Coastguard Worker         mDisplaysWithPointersHidden.erase(displayId);
937*38e8c45fSAndroid Build Coastguard Worker         // We do not unfade the icons here, because we don't know when the last event happened.
938*38e8c45fSAndroid Build Coastguard Worker         return;
939*38e8c45fSAndroid Build Coastguard Worker     }
940*38e8c45fSAndroid Build Coastguard Worker 
941*38e8c45fSAndroid Build Coastguard Worker     mDisplaysWithPointersHidden.emplace(displayId);
942*38e8c45fSAndroid Build Coastguard Worker 
943*38e8c45fSAndroid Build Coastguard Worker     // Hide any icons that are currently visible on the display.
944*38e8c45fSAndroid Build Coastguard Worker     if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
945*38e8c45fSAndroid Build Coastguard Worker         const auto& [_, controller] = *it;
946*38e8c45fSAndroid Build Coastguard Worker         controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
947*38e8c45fSAndroid Build Coastguard Worker     }
948*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [_, controller] : mStylusPointersByDevice) {
949*38e8c45fSAndroid Build Coastguard Worker         if (controller->getDisplayId() == displayId) {
950*38e8c45fSAndroid Build Coastguard Worker             controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
951*38e8c45fSAndroid Build Coastguard Worker         }
952*38e8c45fSAndroid Build Coastguard Worker     }
953*38e8c45fSAndroid Build Coastguard Worker }
954*38e8c45fSAndroid Build Coastguard Worker 
setFocusedDisplay(ui::LogicalDisplayId displayId)955*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::setFocusedDisplay(ui::LogicalDisplayId displayId) {
956*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock lock(getLock());
957*38e8c45fSAndroid Build Coastguard Worker     mCurrentFocusedDisplay = displayId;
958*38e8c45fSAndroid Build Coastguard Worker }
959*38e8c45fSAndroid Build Coastguard Worker 
getMouseControllerConstructor(ui::LogicalDisplayId displayId)960*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
961*38e8c45fSAndroid Build Coastguard Worker         ui::LogicalDisplayId displayId) {
962*38e8c45fSAndroid Build Coastguard Worker     std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
963*38e8c45fSAndroid Build Coastguard Worker             [this, displayId]() REQUIRES(getLock()) {
964*38e8c45fSAndroid Build Coastguard Worker                 auto pc = mPolicy.createPointerController(
965*38e8c45fSAndroid Build Coastguard Worker                         PointerControllerInterface::ControllerType::MOUSE);
966*38e8c45fSAndroid Build Coastguard Worker                 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
967*38e8c45fSAndroid Build Coastguard Worker                     pc->setDisplayViewport(*viewport);
968*38e8c45fSAndroid Build Coastguard Worker                 }
969*38e8c45fSAndroid Build Coastguard Worker                 return pc;
970*38e8c45fSAndroid Build Coastguard Worker             };
971*38e8c45fSAndroid Build Coastguard Worker     return ConstructorDelegate(std::move(ctor));
972*38e8c45fSAndroid Build Coastguard Worker }
973*38e8c45fSAndroid Build Coastguard Worker 
getStylusControllerConstructor(ui::LogicalDisplayId displayId)974*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor(
975*38e8c45fSAndroid Build Coastguard Worker         ui::LogicalDisplayId displayId) {
976*38e8c45fSAndroid Build Coastguard Worker     std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
977*38e8c45fSAndroid Build Coastguard Worker             [this, displayId]() REQUIRES(getLock()) {
978*38e8c45fSAndroid Build Coastguard Worker                 auto pc = mPolicy.createPointerController(
979*38e8c45fSAndroid Build Coastguard Worker                         PointerControllerInterface::ControllerType::STYLUS);
980*38e8c45fSAndroid Build Coastguard Worker                 if (const auto viewport = findViewportByIdLocked(displayId); viewport) {
981*38e8c45fSAndroid Build Coastguard Worker                     pc->setDisplayViewport(*viewport);
982*38e8c45fSAndroid Build Coastguard Worker                 }
983*38e8c45fSAndroid Build Coastguard Worker                 return pc;
984*38e8c45fSAndroid Build Coastguard Worker             };
985*38e8c45fSAndroid Build Coastguard Worker     return ConstructorDelegate(std::move(ctor));
986*38e8c45fSAndroid Build Coastguard Worker }
987*38e8c45fSAndroid Build Coastguard Worker 
populateFakeDisplayTopologyLocked(const std::vector<gui::DisplayInfo> & displayInfos)988*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::populateFakeDisplayTopologyLocked(
989*38e8c45fSAndroid Build Coastguard Worker         const std::vector<gui::DisplayInfo>& displayInfos) {
990*38e8c45fSAndroid Build Coastguard Worker     if (!com::android::input::flags::connected_displays_cursor()) {
991*38e8c45fSAndroid Build Coastguard Worker         return;
992*38e8c45fSAndroid Build Coastguard Worker     }
993*38e8c45fSAndroid Build Coastguard Worker 
994*38e8c45fSAndroid Build Coastguard Worker     if (displayInfos.size() == mTopology.size()) {
995*38e8c45fSAndroid Build Coastguard Worker         bool displaysChanged = false;
996*38e8c45fSAndroid Build Coastguard Worker         for (const auto& displayInfo : displayInfos) {
997*38e8c45fSAndroid Build Coastguard Worker             if (mTopology.find(displayInfo.displayId) == mTopology.end()) {
998*38e8c45fSAndroid Build Coastguard Worker                 displaysChanged = true;
999*38e8c45fSAndroid Build Coastguard Worker                 break;
1000*38e8c45fSAndroid Build Coastguard Worker             }
1001*38e8c45fSAndroid Build Coastguard Worker         }
1002*38e8c45fSAndroid Build Coastguard Worker 
1003*38e8c45fSAndroid Build Coastguard Worker         if (!displaysChanged) {
1004*38e8c45fSAndroid Build Coastguard Worker             return;
1005*38e8c45fSAndroid Build Coastguard Worker         }
1006*38e8c45fSAndroid Build Coastguard Worker     }
1007*38e8c45fSAndroid Build Coastguard Worker 
1008*38e8c45fSAndroid Build Coastguard Worker     // create a fake topology assuming following order
1009*38e8c45fSAndroid Build Coastguard Worker     // default-display (top-edge) -> next-display (right-edge) -> next-display (right-edge) ...
1010*38e8c45fSAndroid Build Coastguard Worker     // This also adds a 100px offset on corresponding edge for better manual testing
1011*38e8c45fSAndroid Build Coastguard Worker     //   ┌────────┐
1012*38e8c45fSAndroid Build Coastguard Worker     //   │ next   ├─────────┐
1013*38e8c45fSAndroid Build Coastguard Worker     // ┌─└───────┐┤ next 2  │ ...
1014*38e8c45fSAndroid Build Coastguard Worker     // │ default │└─────────┘
1015*38e8c45fSAndroid Build Coastguard Worker     // └─────────┘
1016*38e8c45fSAndroid Build Coastguard Worker     mTopology.clear();
1017*38e8c45fSAndroid Build Coastguard Worker 
1018*38e8c45fSAndroid Build Coastguard Worker     // treat default display as base, in real topology it should be the primary-display
1019*38e8c45fSAndroid Build Coastguard Worker     ui::LogicalDisplayId previousDisplay = ui::LogicalDisplayId::DEFAULT;
1020*38e8c45fSAndroid Build Coastguard Worker     for (const auto& displayInfo : displayInfos) {
1021*38e8c45fSAndroid Build Coastguard Worker         if (displayInfo.displayId == ui::LogicalDisplayId::DEFAULT) {
1022*38e8c45fSAndroid Build Coastguard Worker             continue;
1023*38e8c45fSAndroid Build Coastguard Worker         }
1024*38e8c45fSAndroid Build Coastguard Worker         if (previousDisplay == ui::LogicalDisplayId::DEFAULT) {
1025*38e8c45fSAndroid Build Coastguard Worker             mTopology[previousDisplay].push_back(
1026*38e8c45fSAndroid Build Coastguard Worker                     {displayInfo.displayId, DisplayPosition::TOP, 100});
1027*38e8c45fSAndroid Build Coastguard Worker             mTopology[displayInfo.displayId].push_back(
1028*38e8c45fSAndroid Build Coastguard Worker                     {previousDisplay, DisplayPosition::BOTTOM, -100});
1029*38e8c45fSAndroid Build Coastguard Worker         } else {
1030*38e8c45fSAndroid Build Coastguard Worker             mTopology[previousDisplay].push_back(
1031*38e8c45fSAndroid Build Coastguard Worker                     {displayInfo.displayId, DisplayPosition::RIGHT, 100});
1032*38e8c45fSAndroid Build Coastguard Worker             mTopology[displayInfo.displayId].push_back(
1033*38e8c45fSAndroid Build Coastguard Worker                     {previousDisplay, DisplayPosition::LEFT, -100});
1034*38e8c45fSAndroid Build Coastguard Worker         }
1035*38e8c45fSAndroid Build Coastguard Worker         previousDisplay = displayInfo.displayId;
1036*38e8c45fSAndroid Build Coastguard Worker     }
1037*38e8c45fSAndroid Build Coastguard Worker 
1038*38e8c45fSAndroid Build Coastguard Worker     // update default pointer display. In real topology it should be the primary-display
1039*38e8c45fSAndroid Build Coastguard Worker     if (mTopology.find(mDefaultMouseDisplayId) == mTopology.end()) {
1040*38e8c45fSAndroid Build Coastguard Worker         mDefaultMouseDisplayId = ui::LogicalDisplayId::DEFAULT;
1041*38e8c45fSAndroid Build Coastguard Worker     }
1042*38e8c45fSAndroid Build Coastguard Worker }
1043*38e8c45fSAndroid Build Coastguard Worker 
1044*38e8c45fSAndroid Build Coastguard Worker std::optional<std::pair<const DisplayViewport*, float /*offset*/>>
findDestinationDisplayLocked(const ui::LogicalDisplayId sourceDisplayId,const DisplayPosition sourceBoundary,float cursorOffset) const1045*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::findDestinationDisplayLocked(const ui::LogicalDisplayId sourceDisplayId,
1046*38e8c45fSAndroid Build Coastguard Worker                                                    const DisplayPosition sourceBoundary,
1047*38e8c45fSAndroid Build Coastguard Worker                                                    float cursorOffset) const {
1048*38e8c45fSAndroid Build Coastguard Worker     const auto& sourceNode = mTopology.find(sourceDisplayId);
1049*38e8c45fSAndroid Build Coastguard Worker     if (sourceNode == mTopology.end()) {
1050*38e8c45fSAndroid Build Coastguard Worker         // Topology is likely out of sync with viewport info, wait for it to be updated
1051*38e8c45fSAndroid Build Coastguard Worker         LOG(WARNING) << "Source display missing from topology " << sourceDisplayId;
1052*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
1053*38e8c45fSAndroid Build Coastguard Worker     }
1054*38e8c45fSAndroid Build Coastguard Worker     for (const AdjacentDisplay& adjacentDisplay : sourceNode->second) {
1055*38e8c45fSAndroid Build Coastguard Worker         if (adjacentDisplay.position != sourceBoundary) {
1056*38e8c45fSAndroid Build Coastguard Worker             continue;
1057*38e8c45fSAndroid Build Coastguard Worker         }
1058*38e8c45fSAndroid Build Coastguard Worker         const DisplayViewport* destinationViewport =
1059*38e8c45fSAndroid Build Coastguard Worker                 findViewportByIdLocked(adjacentDisplay.displayId);
1060*38e8c45fSAndroid Build Coastguard Worker         if (destinationViewport == nullptr) {
1061*38e8c45fSAndroid Build Coastguard Worker             // Topology is likely out of sync with viewport info, wait for them to be updated
1062*38e8c45fSAndroid Build Coastguard Worker             LOG(WARNING) << "Cannot find viewport for adjacent display "
1063*38e8c45fSAndroid Build Coastguard Worker                          << adjacentDisplay.displayId << "of source display " << sourceDisplayId;
1064*38e8c45fSAndroid Build Coastguard Worker             continue;
1065*38e8c45fSAndroid Build Coastguard Worker         }
1066*38e8c45fSAndroid Build Coastguard Worker         // target position must be within target display boundary
1067*38e8c45fSAndroid Build Coastguard Worker         const int32_t edgeSize =
1068*38e8c45fSAndroid Build Coastguard Worker                 sourceBoundary == DisplayPosition::TOP || sourceBoundary == DisplayPosition::BOTTOM
1069*38e8c45fSAndroid Build Coastguard Worker                 ? (destinationViewport->logicalRight - destinationViewport->logicalLeft)
1070*38e8c45fSAndroid Build Coastguard Worker                 : (destinationViewport->logicalBottom - destinationViewport->logicalTop);
1071*38e8c45fSAndroid Build Coastguard Worker         if (cursorOffset >= adjacentDisplay.offsetPx &&
1072*38e8c45fSAndroid Build Coastguard Worker             cursorOffset <= adjacentDisplay.offsetPx + edgeSize) {
1073*38e8c45fSAndroid Build Coastguard Worker             return std::make_pair(destinationViewport, adjacentDisplay.offsetPx);
1074*38e8c45fSAndroid Build Coastguard Worker         }
1075*38e8c45fSAndroid Build Coastguard Worker     }
1076*38e8c45fSAndroid Build Coastguard Worker     return std::nullopt;
1077*38e8c45fSAndroid Build Coastguard Worker }
1078*38e8c45fSAndroid Build Coastguard Worker 
1079*38e8c45fSAndroid Build Coastguard Worker // --- PointerChoreographer::PointerChoreographerDisplayInfoListener ---
1080*38e8c45fSAndroid Build Coastguard Worker 
onWindowInfosChanged(const gui::WindowInfosUpdate & windowInfosUpdate)1081*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfosChanged(
1082*38e8c45fSAndroid Build Coastguard Worker         const gui::WindowInfosUpdate& windowInfosUpdate) {
1083*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1084*38e8c45fSAndroid Build Coastguard Worker     if (mPointerChoreographer == nullptr) {
1085*38e8c45fSAndroid Build Coastguard Worker         return;
1086*38e8c45fSAndroid Build Coastguard Worker     }
1087*38e8c45fSAndroid Build Coastguard Worker     auto newPrivacySensitiveDisplays =
1088*38e8c45fSAndroid Build Coastguard Worker             getPrivacySensitiveDisplaysFromWindowInfos(windowInfosUpdate.windowInfos);
1089*38e8c45fSAndroid Build Coastguard Worker 
1090*38e8c45fSAndroid Build Coastguard Worker     // PointerChoreographer uses Listener's lock.
1091*38e8c45fSAndroid Build Coastguard Worker     base::ScopedLockAssertion assumeLocked(mPointerChoreographer->getLock());
1092*38e8c45fSAndroid Build Coastguard Worker     if (newPrivacySensitiveDisplays != mPrivacySensitiveDisplays) {
1093*38e8c45fSAndroid Build Coastguard Worker         mPrivacySensitiveDisplays = std::move(newPrivacySensitiveDisplays);
1094*38e8c45fSAndroid Build Coastguard Worker         mPointerChoreographer->onPrivacySensitiveDisplaysChangedLocked(mPrivacySensitiveDisplays);
1095*38e8c45fSAndroid Build Coastguard Worker     }
1096*38e8c45fSAndroid Build Coastguard Worker     mPointerChoreographer->populateFakeDisplayTopologyLocked(windowInfosUpdate.displayInfos);
1097*38e8c45fSAndroid Build Coastguard Worker }
1098*38e8c45fSAndroid Build Coastguard Worker 
setInitialDisplayInfosLocked(const std::vector<gui::WindowInfo> & windowInfos)1099*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfosLocked(
1100*38e8c45fSAndroid Build Coastguard Worker         const std::vector<gui::WindowInfo>& windowInfos) {
1101*38e8c45fSAndroid Build Coastguard Worker     mPrivacySensitiveDisplays = getPrivacySensitiveDisplaysFromWindowInfos(windowInfos);
1102*38e8c45fSAndroid Build Coastguard Worker }
1103*38e8c45fSAndroid Build Coastguard Worker 
1104*38e8c45fSAndroid Build Coastguard Worker std::unordered_set<ui::LogicalDisplayId /*displayId*/>
getPrivacySensitiveDisplaysLocked()1105*38e8c45fSAndroid Build Coastguard Worker PointerChoreographer::PointerChoreographerDisplayInfoListener::getPrivacySensitiveDisplaysLocked() {
1106*38e8c45fSAndroid Build Coastguard Worker     return mPrivacySensitiveDisplays;
1107*38e8c45fSAndroid Build Coastguard Worker }
1108*38e8c45fSAndroid Build Coastguard Worker 
1109*38e8c45fSAndroid Build Coastguard Worker void PointerChoreographer::PointerChoreographerDisplayInfoListener::
onPointerChoreographerDestroyed()1110*38e8c45fSAndroid Build Coastguard Worker         onPointerChoreographerDestroyed() {
1111*38e8c45fSAndroid Build Coastguard Worker     std::scoped_lock _l(mLock);
1112*38e8c45fSAndroid Build Coastguard Worker     mPointerChoreographer = nullptr;
1113*38e8c45fSAndroid Build Coastguard Worker }
1114*38e8c45fSAndroid Build Coastguard Worker 
1115*38e8c45fSAndroid Build Coastguard Worker } // namespace android
1116