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