xref: /aosp_15_r20/frameworks/native/services/inputflinger/PointerChoreographer.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include "InputListener.h"
20 #include "NotifyArgs.h"
21 #include "PointerChoreographerPolicyInterface.h"
22 
23 #include <android-base/thread_annotations.h>
24 #include <gui/WindowInfosListener.h>
25 #include <type_traits>
26 #include <unordered_set>
27 
28 namespace android {
29 
30 struct SpriteIcon;
31 
32 /**
33  * A helper class that wraps a factory method that acts as a constructor for the type returned
34  * by the factory method.
35  */
36 template <typename Factory>
37 struct ConstructorDelegate {
ConstructorDelegateConstructorDelegate38     constexpr ConstructorDelegate(Factory&& factory) : mFactory(std::move(factory)) {}
39 
40     using ConstructedType = std::invoke_result_t<const Factory&>;
ConstructedTypeConstructorDelegate41     constexpr operator ConstructedType() const { return mFactory(); }
42 
43     Factory mFactory;
44 };
45 
46 /**
47  * PointerChoreographer manages the icons shown by the system for input interactions.
48  * This includes showing the mouse cursor, stylus hover icons, and touch spots.
49  * It is responsible for accumulating the location of the mouse cursor, and populating
50  * the cursor position for incoming events, if necessary.
51  */
52 class PointerChoreographerInterface : public InputListenerInterface {
53 public:
54     /**
55      * Set the display that pointers, like the mouse cursor and drawing tablets,
56      * should be drawn on.
57      */
58     virtual void setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) = 0;
59     virtual void setDisplayViewports(const std::vector<DisplayViewport>& viewports) = 0;
60     virtual std::optional<DisplayViewport> getViewportForPointerDevice(
61             ui::LogicalDisplayId associatedDisplayId = ui::LogicalDisplayId::INVALID) = 0;
62     virtual vec2 getMouseCursorPosition(ui::LogicalDisplayId displayId) = 0;
63     virtual void setShowTouchesEnabled(bool enabled) = 0;
64     virtual void setStylusPointerIconEnabled(bool enabled) = 0;
65     /**
66      * Set the icon that is shown for the given pointer. The request may fail in some cases, such
67      * as if the device or display was removed, or if the cursor was moved to a different display.
68      * Returns true if the icon was changed successfully, false otherwise.
69      */
70     virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
71                                 ui::LogicalDisplayId displayId, DeviceId deviceId) = 0;
72     /**
73      * Set whether pointer icons for mice, touchpads, and styluses should be visible on the
74      * given display.
75      */
76     virtual void setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) = 0;
77 
78     /**
79      * Used by Dispatcher to notify changes in the current focused display.
80      */
81     virtual void setFocusedDisplay(ui::LogicalDisplayId displayId) = 0;
82 
83     /**
84      * This method may be called on any thread (usually by the input manager on a binder thread).
85      */
86     virtual void dump(std::string& dump) = 0;
87 };
88 
89 class PointerChoreographer : public PointerChoreographerInterface {
90 public:
91     explicit PointerChoreographer(InputListenerInterface& listener,
92                                   PointerChoreographerPolicyInterface&);
93     ~PointerChoreographer() override;
94 
95     void setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) override;
96     void setDisplayViewports(const std::vector<DisplayViewport>& viewports) override;
97     std::optional<DisplayViewport> getViewportForPointerDevice(
98             ui::LogicalDisplayId associatedDisplayId) override;
99     vec2 getMouseCursorPosition(ui::LogicalDisplayId displayId) override;
100     void setShowTouchesEnabled(bool enabled) override;
101     void setStylusPointerIconEnabled(bool enabled) override;
102     bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
103                         ui::LogicalDisplayId displayId, DeviceId deviceId) override;
104     void setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) override;
105     void setFocusedDisplay(ui::LogicalDisplayId displayId) override;
106 
107     void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
108     void notifyKey(const NotifyKeyArgs& args) override;
109     void notifyMotion(const NotifyMotionArgs& args) override;
110     void notifySwitch(const NotifySwitchArgs& args) override;
111     void notifySensor(const NotifySensorArgs& args) override;
112     void notifyVibratorState(const NotifyVibratorStateArgs& args) override;
113     void notifyDeviceReset(const NotifyDeviceResetArgs& args) override;
114     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override;
115 
116     // TODO(b/362719483) remove these when real topology is available
117     enum class DisplayPosition {
118         RIGHT,
119         TOP,
120         LEFT,
121         BOTTOM,
122         ftl_last = BOTTOM,
123     };
124 
125     struct AdjacentDisplay {
126         ui::LogicalDisplayId displayId;
127         DisplayPosition position;
128         float offsetPx;
129     };
130     void setDisplayTopology(
131             const std::unordered_map<ui::LogicalDisplayId, std::vector<AdjacentDisplay>>&
132                     displayTopology);
133 
134     void dump(std::string& dump) override;
135 
136 private:
137     using PointerDisplayChange =
138             std::optional<std::tuple<ui::LogicalDisplayId /*displayId*/, vec2 /*cursorPosition*/>>;
139 
140     // PointerChoreographer's DisplayInfoListener can outlive the PointerChoreographer because when
141     // the listener is registered and called from display thread, a strong pointer to the listener
142     // (which can extend its lifecycle) is given away.
143     // If we use two locks it can also cause deadlocks due to race in acquiring them between the
144     // display and reader thread.
145     // To avoid these problems we use DisplayInfoListener's lock in PointerChoreographer.
146     std::mutex& getLock() const;
147 
148     [[nodiscard]] PointerDisplayChange updatePointerControllersLocked() REQUIRES(getLock());
149     [[nodiscard]] PointerDisplayChange calculatePointerDisplayChangeToNotify() REQUIRES(getLock());
150     const DisplayViewport* findViewportByIdLocked(ui::LogicalDisplayId displayId) const
151             REQUIRES(getLock());
152     ui::LogicalDisplayId getTargetMouseDisplayLocked(ui::LogicalDisplayId associatedDisplayId) const
153             REQUIRES(getLock());
154     std::pair<ui::LogicalDisplayId /*displayId*/, PointerControllerInterface&>
155     ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) REQUIRES(getLock());
156     InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(getLock());
157     bool canUnfadeOnDisplay(ui::LogicalDisplayId displayId) REQUIRES(getLock());
158 
159     void fadeMouseCursorOnKeyPress(const NotifyKeyArgs& args);
160     NotifyMotionArgs processMotion(const NotifyMotionArgs& args);
161     NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
162     NotifyMotionArgs processTouchpadEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
163     void processDrawingTabletEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
164     void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
165     void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
166     void processPointerDeviceMotionEventLocked(NotifyMotionArgs& newArgs,
167                                                PointerControllerInterface& pc) REQUIRES(getLock());
168     void processDeviceReset(const NotifyDeviceResetArgs& args);
169     void onControllerAddedOrRemovedLocked() REQUIRES(getLock());
170     void onPrivacySensitiveDisplaysChangedLocked(
171             const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays)
172             REQUIRES(getLock());
173 
174     void handleUnconsumedDeltaLocked(PointerControllerInterface& pc, const vec2& unconsumedDelta)
175             REQUIRES(getLock());
176 
177     void populateFakeDisplayTopologyLocked(const std::vector<gui::DisplayInfo>& displayInfos)
178             REQUIRES(getLock());
179 
180     std::optional<std::pair<const DisplayViewport*, float /*offset*/>> findDestinationDisplayLocked(
181             const ui::LogicalDisplayId sourceDisplayId, const DisplayPosition sourceBoundary,
182             float cursorOffset) const REQUIRES(getLock());
183 
184     static vec2 calculateDestinationPosition(const DisplayViewport& destinationViewport,
185                                              float pointerOffset, DisplayPosition sourceBoundary);
186 
187     std::unordered_map<ui::LogicalDisplayId, std::vector<AdjacentDisplay>> mTopology
188             GUARDED_BY(getLock());
189 
190     /* This listener keeps tracks of visible privacy sensitive displays and updates the
191      * choreographer if there are any changes.
192      *
193      * Listener uses mListenerLock to guard all private data as choreographer and SurfaceComposer
194      * both can call into the listener. To prevent deadlocks Choreographer can call listener with
195      * its lock held, but listener must not call choreographer with its lock.
196      */
197     class PointerChoreographerDisplayInfoListener : public gui::WindowInfosListener {
198     public:
PointerChoreographerDisplayInfoListener(PointerChoreographer * pc)199         explicit PointerChoreographerDisplayInfoListener(PointerChoreographer* pc)
200               : mPointerChoreographer(pc){};
201         void onWindowInfosChanged(const gui::WindowInfosUpdate&) override;
202         void setInitialDisplayInfosLocked(const std::vector<gui::WindowInfo>& windowInfos)
203                 REQUIRES(mLock);
204         std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysLocked()
205                 REQUIRES(mLock);
206         void onPointerChoreographerDestroyed();
207 
208         // This lock is also used by PointerChoreographer. See PointerChoreographer::getLock().
209         std::mutex mLock;
210 
211     private:
212         PointerChoreographer* mPointerChoreographer GUARDED_BY(mLock);
213         std::unordered_set<ui::LogicalDisplayId /*displayId*/> mPrivacySensitiveDisplays
214                 GUARDED_BY(mLock);
215     };
216 
217     using ControllerConstructor =
218             ConstructorDelegate<std::function<std::shared_ptr<PointerControllerInterface>()>>;
219     ControllerConstructor mTouchControllerConstructor GUARDED_BY(getLock());
220     ControllerConstructor getMouseControllerConstructor(ui::LogicalDisplayId displayId)
221             REQUIRES(getLock());
222     ControllerConstructor getStylusControllerConstructor(ui::LogicalDisplayId displayId)
223             REQUIRES(getLock());
224 
225     InputListenerInterface& mNextListener;
226     PointerChoreographerPolicyInterface& mPolicy;
227 
228     std::map<ui::LogicalDisplayId, std::shared_ptr<PointerControllerInterface>>
229             mMousePointersByDisplay GUARDED_BY(getLock());
230     std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mTouchPointersByDevice
231             GUARDED_BY(getLock());
232     std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mStylusPointersByDevice
233             GUARDED_BY(getLock());
234     std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice
235             GUARDED_BY(getLock());
236 
237     ui::LogicalDisplayId mDefaultMouseDisplayId GUARDED_BY(getLock());
238     ui::LogicalDisplayId mNotifiedPointerDisplayId GUARDED_BY(getLock());
239     std::vector<InputDeviceInfo> mInputDeviceInfos GUARDED_BY(getLock());
240     std::set<DeviceId> mMouseDevices GUARDED_BY(getLock());
241     std::vector<DisplayViewport> mViewports GUARDED_BY(getLock());
242     bool mShowTouchesEnabled GUARDED_BY(getLock());
243     bool mStylusPointerIconEnabled GUARDED_BY(getLock());
244     std::set<ui::LogicalDisplayId /*displayId*/> mDisplaysWithPointersHidden;
245     ui::LogicalDisplayId mCurrentFocusedDisplay GUARDED_BY(getLock());
246 
247 protected:
248     using WindowListenerRegisterConsumer = std::function<std::vector<gui::WindowInfo>(
249             const sp<android::gui::WindowInfosListener>&)>;
250     using WindowListenerUnregisterConsumer =
251             std::function<void(const sp<android::gui::WindowInfosListener>&)>;
252     explicit PointerChoreographer(InputListenerInterface& listener,
253                                   PointerChoreographerPolicyInterface&,
254                                   const WindowListenerRegisterConsumer& registerListener,
255                                   const WindowListenerUnregisterConsumer& unregisterListener);
256 
257 private:
258     // WindowInfoListener object should always exist while PointerChoreographer exists, because we
259     // need to use the lock from it. But we don't always need to register the listener.
260     bool mIsWindowInfoListenerRegistered GUARDED_BY(getLock());
261     const sp<PointerChoreographerDisplayInfoListener> mWindowInfoListener;
262     const WindowListenerRegisterConsumer mRegisterListener;
263     const WindowListenerUnregisterConsumer mUnregisterListener;
264 };
265 
266 } // namespace android
267