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