• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <input/DisplayTopologyGraph.h>
26 #include <type_traits>
27 #include <unordered_set>
28 
29 namespace android {
30 
31 struct SpriteIcon;
32 
33 /**
34  * A helper class that wraps a factory method that acts as a constructor for the type returned
35  * by the factory method.
36  */
37 template <typename Factory>
38 struct ConstructorDelegate {
ConstructorDelegateConstructorDelegate39     constexpr ConstructorDelegate(Factory&& factory) : mFactory(std::move(factory)) {}
40 
41     using ConstructedType = std::invoke_result_t<const Factory&>;
ConstructedTypeConstructorDelegate42     constexpr operator ConstructedType() const { return mFactory(); }
43 
44     Factory mFactory;
45 };
46 
47 /**
48  * PointerChoreographer manages the icons shown by the system for input interactions.
49  * This includes showing the mouse cursor, stylus hover icons, and touch spots.
50  * It is responsible for accumulating the location of the mouse cursor, and populating
51  * the cursor position for incoming events, if necessary.
52  */
53 class PointerChoreographerInterface : public InputListenerInterface {
54 public:
55     /**
56      * Set the display that pointers, like the mouse cursor and drawing tablets,
57      * should be drawn on.
58      */
59     virtual void setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) = 0;
60     virtual void setDisplayViewports(const std::vector<DisplayViewport>& viewports) = 0;
61     virtual std::optional<DisplayViewport> getViewportForPointerDevice(
62             ui::LogicalDisplayId associatedDisplayId = ui::LogicalDisplayId::INVALID) = 0;
63     virtual vec2 getMouseCursorPosition(ui::LogicalDisplayId displayId) = 0;
64     virtual void setShowTouchesEnabled(bool enabled) = 0;
65     virtual void setStylusPointerIconEnabled(bool enabled) = 0;
66     /**
67      * Set the icon that is shown for the given pointer. The request may fail in some cases, such
68      * as if the device or display was removed, or if the cursor was moved to a different display.
69      * Returns true if the icon was changed successfully, false otherwise.
70      */
71     virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
72                                 ui::LogicalDisplayId displayId, DeviceId deviceId) = 0;
73     /**
74      * Set whether pointer icons for mice, touchpads, and styluses should be visible on the
75      * given display.
76      */
77     virtual void setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) = 0;
78 
79     /**
80      * Used by Dispatcher to notify changes in the current focused display.
81      */
82     virtual void setFocusedDisplay(ui::LogicalDisplayId displayId) = 0;
83 
84     /*
85      * Used by InputManager to notify changes in the DisplayTopology
86      */
87     virtual void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) = 0;
88 
89     /**
90      * This method may be called on any thread (usually by the input manager on a binder thread).
91      */
92     virtual void dump(std::string& dump) = 0;
93 
94     /**
95      * Enables motion event filter before pointer coordinates are determined.
96      */
97     virtual void setAccessibilityPointerMotionFilterEnabled(bool enabled) = 0;
98 };
99 
100 class PointerChoreographer : public PointerChoreographerInterface {
101 public:
102     explicit PointerChoreographer(InputListenerInterface& listener,
103                                   PointerChoreographerPolicyInterface&);
104     ~PointerChoreographer() override;
105 
106     void setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) override;
107     void setDisplayViewports(const std::vector<DisplayViewport>& viewports) override;
108     std::optional<DisplayViewport> getViewportForPointerDevice(
109             ui::LogicalDisplayId associatedDisplayId) override;
110     vec2 getMouseCursorPosition(ui::LogicalDisplayId displayId) override;
111     void setShowTouchesEnabled(bool enabled) override;
112     void setStylusPointerIconEnabled(bool enabled) override;
113     bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
114                         ui::LogicalDisplayId displayId, DeviceId deviceId) override;
115     void setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) override;
116     void setFocusedDisplay(ui::LogicalDisplayId displayId) override;
117     void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph);
118     void setAccessibilityPointerMotionFilterEnabled(bool enabled) override;
119 
120     void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
121     void notifyKey(const NotifyKeyArgs& args) override;
122     void notifyMotion(const NotifyMotionArgs& args) override;
123     void notifySwitch(const NotifySwitchArgs& args) override;
124     void notifySensor(const NotifySensorArgs& args) override;
125     void notifyVibratorState(const NotifyVibratorStateArgs& args) override;
126     void notifyDeviceReset(const NotifyDeviceResetArgs& args) override;
127     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override;
128 
129     void dump(std::string& dump) override;
130 
131 private:
132     using PointerDisplayChange =
133             std::optional<std::tuple<ui::LogicalDisplayId /*displayId*/, vec2 /*cursorPosition*/>>;
134 
135     // PointerChoreographer's DisplayInfoListener can outlive the PointerChoreographer because when
136     // the listener is registered and called from display thread, a strong pointer to the listener
137     // (which can extend its lifecycle) is given away.
138     // If we use two locks it can also cause deadlocks due to race in acquiring them between the
139     // display and reader thread.
140     // To avoid these problems we use DisplayInfoListener's lock in PointerChoreographer.
141     std::mutex& getLock() const;
142 
143     [[nodiscard]] PointerDisplayChange updatePointerControllersLocked() REQUIRES(getLock());
144     [[nodiscard]] PointerDisplayChange calculatePointerDisplayChangeToNotify() REQUIRES(getLock());
145     const DisplayViewport* findViewportByIdLocked(ui::LogicalDisplayId displayId) const
146             REQUIRES(getLock());
147     ui::LogicalDisplayId getTargetMouseDisplayLocked(ui::LogicalDisplayId associatedDisplayId) const
148             REQUIRES(getLock());
149     std::pair<ui::LogicalDisplayId /*displayId*/, PointerControllerInterface&>
150     ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) REQUIRES(getLock());
151     InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(getLock());
152     bool canUnfadeOnDisplay(ui::LogicalDisplayId displayId) REQUIRES(getLock());
153 
154     void fadeMouseCursorOnKeyPress(const NotifyKeyArgs& args);
155     NotifyMotionArgs processMotion(const NotifyMotionArgs& args);
156     NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
157     NotifyMotionArgs processTouchpadEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
158     void processDrawingTabletEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
159     void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
160     void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
161     void processPointerDeviceMotionEventLocked(NotifyMotionArgs& newArgs,
162                                                PointerControllerInterface& pc) REQUIRES(getLock());
163     void processDeviceReset(const NotifyDeviceResetArgs& args);
164     void onControllerAddedOrRemovedLocked() REQUIRES(getLock());
165     void onPrivacySensitiveDisplaysChangedLocked(
166             const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays)
167             REQUIRES(getLock());
168 
169     void handleUnconsumedDeltaLocked(PointerControllerInterface& pc, const vec2& unconsumedDelta)
170             REQUIRES(getLock());
171 
172     std::optional<std::pair<const DisplayViewport*, float /*offsetPx*/>>
173     findDestinationDisplayLocked(const ui::LogicalDisplayId sourceDisplayId,
174                                  const DisplayTopologyPosition sourceBoundary,
175                                  int32_t sourceCursorOffsetPx) const REQUIRES(getLock());
176 
177     vec2 filterPointerMotionForAccessibilityLocked(const vec2& current, const vec2& delta,
178                                                    const ui::LogicalDisplayId& displayId)
179             REQUIRES(getLock());
180 
181     /* Topology is initialized with default-constructed value, which is an empty topology. Till we
182      * receive setDisplayTopology call.
183      * Meanwhile Choreographer will treat every display as independent disconnected display.
184      */
185     DisplayTopologyGraph mTopology GUARDED_BY(getLock());
186 
187     /* This listener keeps tracks of visible privacy sensitive displays and updates the
188      * choreographer if there are any changes.
189      *
190      * Listener uses mListenerLock to guard all private data as choreographer and SurfaceComposer
191      * both can call into the listener. To prevent deadlocks Choreographer can call listener with
192      * its lock held, but listener must not call choreographer with its lock.
193      */
194     class PointerChoreographerDisplayInfoListener : public gui::WindowInfosListener {
195     public:
PointerChoreographerDisplayInfoListener(PointerChoreographer * pc)196         explicit PointerChoreographerDisplayInfoListener(PointerChoreographer* pc)
197               : mPointerChoreographer(pc){};
198         void onWindowInfosChanged(const gui::WindowInfosUpdate&) override;
199         void setInitialDisplayInfosLocked(const std::vector<gui::WindowInfo>& windowInfos)
200                 REQUIRES(mLock);
201         std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysLocked()
202                 REQUIRES(mLock);
203         void onPointerChoreographerDestroyed();
204 
205         // This lock is also used by PointerChoreographer. See PointerChoreographer::getLock().
206         std::mutex mLock;
207 
208     private:
209         PointerChoreographer* mPointerChoreographer GUARDED_BY(mLock);
210         std::unordered_set<ui::LogicalDisplayId /*displayId*/> mPrivacySensitiveDisplays
211                 GUARDED_BY(mLock);
212     };
213 
214     using ControllerConstructor =
215             ConstructorDelegate<std::function<std::shared_ptr<PointerControllerInterface>()>>;
216     ControllerConstructor mTouchControllerConstructor GUARDED_BY(getLock());
217     ControllerConstructor getMouseControllerConstructor(ui::LogicalDisplayId displayId)
218             REQUIRES(getLock());
219     ControllerConstructor getStylusControllerConstructor(ui::LogicalDisplayId displayId)
220             REQUIRES(getLock());
221 
222     InputListenerInterface& mNextListener;
223     PointerChoreographerPolicyInterface& mPolicy;
224 
225     std::map<ui::LogicalDisplayId, std::shared_ptr<PointerControllerInterface>>
226             mMousePointersByDisplay GUARDED_BY(getLock());
227     std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mTouchPointersByDevice
228             GUARDED_BY(getLock());
229     std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mStylusPointersByDevice
230             GUARDED_BY(getLock());
231     std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice
232             GUARDED_BY(getLock());
233 
234     // In connected displays scenario, this tracks the latest display the cursor is at, within the
235     // DisplayTopology. By default, this will be set to topology primary display, and updated when
236     // mouse crossed to another display.
237     // In non-connected displays scenario, this will be treated as the default display cursor
238     // will be on, when mouse doesn't have associated display.
239     ui::LogicalDisplayId mCurrentMouseDisplayId GUARDED_BY(getLock());
240     ui::LogicalDisplayId mNotifiedPointerDisplayId GUARDED_BY(getLock());
241     std::vector<InputDeviceInfo> mInputDeviceInfos GUARDED_BY(getLock());
242     std::set<DeviceId> mMouseDevices GUARDED_BY(getLock());
243     std::vector<DisplayViewport> mViewports GUARDED_BY(getLock());
244     bool mShowTouchesEnabled GUARDED_BY(getLock());
245     bool mStylusPointerIconEnabled GUARDED_BY(getLock());
246     bool mPointerMotionFilterEnabled GUARDED_BY(getLock());
247     std::set<ui::LogicalDisplayId /*displayId*/> mDisplaysWithPointersHidden;
248     ui::LogicalDisplayId mCurrentFocusedDisplay GUARDED_BY(getLock());
249 
250 protected:
251     using WindowListenerRegisterConsumer = std::function<std::vector<gui::WindowInfo>(
252             const sp<android::gui::WindowInfosListener>&)>;
253     using WindowListenerUnregisterConsumer =
254             std::function<void(const sp<android::gui::WindowInfosListener>&)>;
255     explicit PointerChoreographer(InputListenerInterface& listener,
256                                   PointerChoreographerPolicyInterface&,
257                                   const WindowListenerRegisterConsumer& registerListener,
258                                   const WindowListenerUnregisterConsumer& unregisterListener);
259 
260 private:
261     // WindowInfoListener object should always exist while PointerChoreographer exists, because we
262     // need to use the lock from it. But we don't always need to register the listener.
263     bool mIsWindowInfoListenerRegistered GUARDED_BY(getLock());
264     const sp<PointerChoreographerDisplayInfoListener> mWindowInfoListener;
265     const WindowListenerRegisterConsumer mRegisterListener;
266     const WindowListenerUnregisterConsumer mUnregisterListener;
267 };
268 
269 } // namespace android
270