diff options
21 files changed, 468 insertions, 253 deletions
diff --git a/include/android/choreographer.h b/include/android/choreographer.h index 01f523b536..bec3283cd8 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -17,8 +17,20 @@ /** * @addtogroup Choreographer * - * Choreographer coordinates the timing of frame rendering. This is the C version of the - * android.view.Choreographer object in Java. + * Choreographer coordinates the timing of frame rendering. This is the C + * version of the android.view.Choreographer object in Java. If you do not use + * Choreographer to pace your render loop, you may render too quickly for the + * display, increasing latency between frame submission and presentation. + * + * Input events are guaranteed to be processed before the frame callback is + * called, and will not be run concurrently. Input and sensor events should not + * be handled in the Choregrapher callback. + * + * The frame callback is also the appropriate place to run any per-frame state + * update logic. For example, in a game, the frame callback should be + * responsible for updating things like physics, AI, game state, and rendering + * the frame. Input and sensors should be handled separately via callbacks + * registered with AInputQueue and ASensorManager. * * As of API level 33, apps can follow proper frame pacing and even choose a future frame to render. * The API is used as follows: @@ -38,6 +50,11 @@ * 4. SurfaceFlinger attempts to follow the chosen frame timeline, by not applying transactions or * latching buffers before the desired presentation time. * + * On older devices, AChoreographer_postFrameCallback64 or + * AChoreographer_postFrameCallback can be used to lesser effect. They cannot be + * used to precisely plan your render timeline, but will rate limit to avoid + * overloading the display pipeline and increasing frame latency. + * * @{ */ @@ -129,14 +146,46 @@ typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, voi AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24); /** - * Deprecated: Use AChoreographer_postFrameCallback64 instead. + * Post a callback to be run when the application should begin rendering the + * next frame. The data pointer provided will be passed to the callback function + * when it's called. + * + * The callback will only be run for the next frame, not all subsequent frames, + * so to render continuously the callback should itself call + * AChoreographer_postFrameCallback. + * + * \bug The callback receives the frame time in nanoseconds as a long. On 32-bit + * systems, long is 32-bit, so the frame time will roll over roughly every two + * seconds. If your minSdkVersion is 29 or higher, switch to + * AChoreographer_postFrameCallback64, which uses a 64-bit frame time for all + * platforms. For older OS versions, you must combine the argument with the + * upper bits of clock_gettime(CLOCK_MONOTONIC, ...) on 32-bit systems. + * + * \deprecated Use AChoreographer_postFrameCallback64, which does not have the + * bug described above. */ void AChoreographer_postFrameCallback(AChoreographer* choreographer, AChoreographer_frameCallback callback, void* data) __INTRODUCED_IN(24) __DEPRECATED_IN(29, "Use AChoreographer_postFrameCallback64 instead"); /** - * Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead. + * Post a callback to be run when the application should begin rendering the + * next frame following the specified delay. The data pointer provided will be + * passed to the callback function when it's called. + * + * The callback will only be run for the next frame after the delay, not all + * subsequent frames, so to render continuously the callback should itself call + * AChoreographer_postFrameCallbackDelayed. + * + * \bug The callback receives the frame time in nanoseconds as a long. On 32-bit + * systems, long is 32-bit, so the frame time will roll over roughly every two + * seconds. If your minSdkVersion is 29 or higher, switch to + * AChoreographer_postFrameCallbackDelayed64, which uses a 64-bit frame time for + * all platforms. For older OS versions, you must combine the argument with the + * upper bits of clock_gettime(CLOCK_MONOTONIC, ...) on 32-bit systems. + * + * \deprecated Use AChoreographer_postFrameCallbackDelayed64, which does not + * have the bug described above. */ void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, AChoreographer_frameCallback callback, void* data, @@ -144,8 +193,13 @@ void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, __DEPRECATED_IN(29, "Use AChoreographer_postFrameCallbackDelayed64 instead"); /** - * Post a callback to be run on the next frame. The data pointer provided will - * be passed to the callback function when it's called. + * Post a callback to be run when the application should begin rendering the + * next frame. The data pointer provided will be passed to the callback function + * when it's called. + * + * The callback will only be run on the next frame, not all subsequent frames, + * so to render continuously the callback should itself call + * AChoreographer_postFrameCallback64. * * Available since API level 29. */ @@ -154,9 +208,13 @@ void AChoreographer_postFrameCallback64(AChoreographer* choreographer, __INTRODUCED_IN(29); /** - * Post a callback to be run on the frame following the specified delay. The - * data pointer provided will be passed to the callback function when it's - * called. + * Post a callback to be run when the application should begin rendering the + * next frame following the specified delay. The data pointer provided will be + * passed to the callback function when it's called. + * + * The callback will only be run for the next frame after the delay, not all + * subsequent frames, so to render continuously the callback should itself call + * AChoreographer_postFrameCallbackDelayed64. * * Available since API level 29. */ @@ -165,8 +223,13 @@ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, uint32_t delayMillis) __INTRODUCED_IN(29); /** - * Posts a callback to be run on the next frame. The data pointer provided will - * be passed to the callback function when it's called. + * Posts a callback to be run when the application should begin rendering the + * next frame. The data pointer provided will be passed to the callback function + * when it's called. + * + * The callback will only be run for the next frame, not all subsequent frames, + * so to render continuously the callback should itself call + * AChoreographer_postVsyncCallback. * * Available since API level 33. */ diff --git a/include/android/looper.h b/include/android/looper.h index 6a02916fb3..d80a3660a6 100644 --- a/include/android/looper.h +++ b/include/android/looper.h @@ -182,23 +182,27 @@ typedef int (*ALooper_callbackFunc)(int fd, int events, void* data); * If the timeout is zero, returns immediately without blocking. * If the timeout is negative, waits indefinitely until an event appears. * - * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before + * Returns ALOOPER_POLL_WAKE if the poll was awoken using ALooper_wake() before * the timeout expired and no callbacks were invoked and no other file - * descriptors were ready. + * descriptors were ready. **All return values may also imply + * ALOOPER_POLL_WAKE.** * - * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked. + * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked. The poll + * may also have been explicitly woken by ALooper_wake. * - * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given - * timeout expired. + * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given timeout + * expired. The poll may also have been explicitly woken by ALooper_wake. * - * Returns ALOOPER_POLL_ERROR if an error occurred. + * Returns ALOOPER_POLL_ERROR if the calling thread has no associated Looper or + * for unrecoverable internal errors. The poll may also have been explicitly + * woken by ALooper_wake. * - * Returns a value >= 0 containing an identifier (the same identifier - * `ident` passed to ALooper_addFd()) if its file descriptor has data - * and it has no callback function (requiring the caller here to - * handle it). In this (and only this) case outFd, outEvents and - * outData will contain the poll events and data associated with the - * fd, otherwise they will be set to NULL. + * Returns a value >= 0 containing an identifier (the same identifier `ident` + * passed to ALooper_addFd()) if its file descriptor has data and it has no + * callback function (requiring the caller here to handle it). In this (and + * only this) case outFd, outEvents and outData will contain the poll events and + * data associated with the fd, otherwise they will be set to NULL. The poll may + * also have been explicitly woken by ALooper_wake. * * This method does not return until it has finished invoking the appropriate callbacks * for all file descriptors that were signalled. @@ -210,11 +214,21 @@ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa * data has been consumed or a file descriptor is available with no callback. * This function will never return ALOOPER_POLL_CALLBACK. * - * Removed in API 34 as ALooper_pollAll can swallow ALooper_wake calls. - * Use ALooper_pollOnce instead. + * This API cannot be used safely, but a safe alternative exists (see below). As + * such, new builds will not be able to call this API and must migrate to the + * safe API. Binary compatibility is preserved to support already-compiled apps. + * + * \bug ALooper_pollAll will not wake in response to ALooper_wake calls if it + * also handles another event at the same time. + * + * \deprecated Calls to ALooper_pollAll should be replaced with + * ALooper_pollOnce. If you call ALooper_pollOnce in a loop, you *must* treat + * all return values as if they also indicate ALOOPER_POLL_WAKE. */ int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) - __REMOVED_IN(1, "ALooper_pollAll may ignore wakes. Use ALooper_pollOnce instead. See https://github.com/android/ndk/discussions/2020 for more information"); + __REMOVED_IN(1, + "ALooper_pollAll may ignore wakes. Use ALooper_pollOnce instead. See " + "The API documentation for more information"); /** * Wakes the poll asynchronously. diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 6ccc6cafb6..81f6a585ab 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -40,6 +40,9 @@ namespace bpf { static constexpr uint64_t NSEC_PER_SEC = 1000000000; static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365; +// Declare busy loop variable globally to prevent removal during optimization +static long sum __attribute__((used)) = 0; + using std::vector; class TimeInStateTest : public testing::Test { @@ -576,7 +579,7 @@ uint64_t timeNanos() { // Keeps CPU busy with some number crunching void useCpu() { - long sum = 0; + sum = 0; for (int i = 0; i < 100000; i++) { sum *= i; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index de841ba2b8..79b8560590 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -5363,31 +5363,32 @@ void InputDispatcher::setInputWindowsLocked( onFocusChangedLocked(*changes, traceContext.getTracker(), removedFocusedWindowHandle); } - std::unordered_map<int32_t, TouchState>::iterator stateIt = - mTouchStatesByDisplay.find(displayId); - if (stateIt != mTouchStatesByDisplay.end()) { - TouchState& state = stateIt->second; + if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) { + TouchState& state = it->second; for (size_t i = 0; i < state.windows.size();) { TouchedWindow& touchedWindow = state.windows[i]; - if (getWindowHandleLocked(touchedWindow.windowHandle) == nullptr) { - LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName() - << " in display %" << displayId; - CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "touched window was removed", traceContext.getTracker()); - synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options); - // Since we are about to drop the touch, cancel the events for the wallpaper as - // well. - if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) && - touchedWindow.windowHandle->getInfo()->inputConfig.test( - gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { - if (const auto& ww = state.getWallpaperWindow(); ww) { + if (getWindowHandleLocked(touchedWindow.windowHandle) != nullptr) { + i++; + continue; + } + LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName() + << " in display %" << displayId; + CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + "touched window was removed", traceContext.getTracker()); + synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options); + // Since we are about to drop the touch, cancel the events for the wallpaper as + // well. + if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) && + touchedWindow.windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { + for (const DeviceId deviceId : touchedWindow.getTouchingDeviceIds()) { + if (const auto& ww = state.getWallpaperWindow(deviceId); ww != nullptr) { + options.deviceId = deviceId; synthesizeCancelationEventsForWindowLocked(ww, options); } } - state.windows.erase(state.windows.begin() + i); - } else { - ++i; } + state.windows.erase(state.windows.begin() + i); } // If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We @@ -5662,13 +5663,13 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s ALOGD("Touch transfer failed because from window is not being touched."); return false; } - std::set<int32_t> deviceIds = touchedWindow->getTouchingDeviceIds(); + std::set<DeviceId> deviceIds = touchedWindow->getTouchingDeviceIds(); if (deviceIds.size() != 1) { LOG(INFO) << "Can't transfer touch. Currently touching devices: " << dumpSet(deviceIds) << " for window: " << touchedWindow->dump(); return false; } - const int32_t deviceId = *deviceIds.begin(); + const DeviceId deviceId = *deviceIds.begin(); const sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle; const sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(toToken, displayId); @@ -5722,13 +5723,18 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s "transferring touch from this window to another window", traceContext.getTracker()); synthesizeCancelationEventsForWindowLocked(fromWindowHandle, options, fromConnection); - synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection, - newTargetFlags, - traceContext.getTracker()); // Check if the wallpaper window should deliver the corresponding event. transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle, *state, deviceId, pointers, traceContext.getTracker()); + + // Because new window may have a wallpaper window, it will merge input state from it + // parent window, after this the firstNewPointerIdx in input state will be reset, then + // it will cause new move event be thought inconsistent, so we should synthesize the + // down event after it reset. + synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection, + newTargetFlags, + traceContext.getTracker()); } } // release lock @@ -7039,7 +7045,7 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<WindowInfoHandle>& oldWindowHandle, const sp<WindowInfoHandle>& newWindowHandle, - TouchState& state, int32_t deviceId, + TouchState& state, DeviceId deviceId, const PointerProperties& pointerProperties, std::vector<InputTarget>& targets) const { std::vector<PointerProperties> pointers{pointerProperties}; @@ -7049,7 +7055,7 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl newWindowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); const sp<WindowInfoHandle> oldWallpaper = - oldHasWallpaper ? state.getWallpaperWindow() : nullptr; + oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr; const sp<WindowInfoHandle> newWallpaper = newHasWallpaper ? findWallpaperWindowBelow(newWindowHandle) : nullptr; if (oldWallpaper == newWallpaper) { @@ -7075,7 +7081,7 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl void InputDispatcher::transferWallpaperTouch( ftl::Flags<InputTarget::Flags> oldTargetFlags, ftl::Flags<InputTarget::Flags> newTargetFlags, const sp<WindowInfoHandle> fromWindowHandle, - const sp<WindowInfoHandle> toWindowHandle, TouchState& state, int32_t deviceId, + const sp<WindowInfoHandle> toWindowHandle, TouchState& state, DeviceId deviceId, const std::vector<PointerProperties>& pointers, const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) { const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) && @@ -7086,7 +7092,7 @@ void InputDispatcher::transferWallpaperTouch( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); const sp<WindowInfoHandle> oldWallpaper = - oldHasWallpaper ? state.getWallpaperWindow() : nullptr; + oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr; const sp<WindowInfoHandle> newWallpaper = newHasWallpaper ? findWallpaperWindowBelow(toWindowHandle) : nullptr; if (oldWallpaper == newWallpaper) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 3579a67c96..3d127c296a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -701,14 +701,14 @@ private: void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<android::gui::WindowInfoHandle>& oldWindowHandle, const sp<android::gui::WindowInfoHandle>& newWindowHandle, - TouchState& state, int32_t deviceId, + TouchState& state, DeviceId deviceId, const PointerProperties& pointerProperties, std::vector<InputTarget>& targets) const REQUIRES(mLock); void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, ftl::Flags<InputTarget::Flags> newTargetFlags, const sp<android::gui::WindowInfoHandle> fromWindowHandle, const sp<android::gui::WindowInfoHandle> toWindowHandle, - TouchState& state, int32_t deviceId, + TouchState& state, DeviceId deviceId, const std::vector<PointerProperties>& pointers, const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 296c334583..0c9ad3c7b7 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -211,9 +211,11 @@ bool TouchState::isSlippery(DeviceId deviceId) const { return haveSlipperyForegroundWindow; } -sp<WindowInfoHandle> TouchState::getWallpaperWindow() const { - for (size_t i = 0; i < windows.size(); i++) { - const TouchedWindow& window = windows[i]; +sp<WindowInfoHandle> TouchState::getWallpaperWindow(DeviceId deviceId) const { + for (const auto& window : windows) { + if (!window.hasTouchingPointers(deviceId)) { + continue; + } if (window.windowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::IS_WALLPAPER)) { return window.windowHandle; diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 9ddb4e206f..9d4bb3d943 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -66,7 +66,7 @@ struct TouchState { sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle(DeviceId deviceId) const; bool isSlippery(DeviceId deviceId) const; - sp<android::gui::WindowInfoHandle> getWallpaperWindow() const; + sp<android::gui::WindowInfoHandle> getWallpaperWindow(DeviceId deviceId) const; const TouchedWindow& getTouchedWindow( const sp<android::gui::WindowInfoHandle>& windowHandle) const; // Whether any of the windows are currently being touched diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 77e672c6bc..4d8ed99eb4 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -61,9 +61,6 @@ struct InputReaderConfiguration { // The display size or orientation changed. DISPLAY_INFO = 1u << 2, - // The visible touches option changed. - SHOW_TOUCHES = 1u << 3, - // The keyboard layouts must be reloaded. KEYBOARD_LAYOUTS = 1u << 4, @@ -214,9 +211,6 @@ struct InputReaderConfiguration { // will cover this portion of the display diagonal. float pointerGestureZoomSpeedRatio; - // True to show the location of touches on the touch screen as spots. - bool showTouches; - // The latest request to enable or disable Pointer Capture. PointerCaptureRequest pointerCaptureRequest; @@ -268,7 +262,6 @@ struct InputReaderConfiguration { pointerGestureSwipeMaxWidthRatio(0.25f), pointerGestureMovementSpeedRatio(0.8f), pointerGestureZoomSpeedRatio(0.3f), - showTouches(false), pointerCaptureRequest(), touchpadPointerSpeed(0), touchpadNaturalScrollingEnabled(true), @@ -449,10 +442,6 @@ public: /* Gets the input reader configuration. */ virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; - /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ - virtual std::shared_ptr<PointerControllerInterface> obtainPointerController( - int32_t deviceId) = 0; - /* Notifies the input reader policy that some input devices have changed * and provides information about all current input devices. */ diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h index 6b26e81637..c1467b3eed 100644 --- a/services/inputflinger/include/PointerControllerInterface.h +++ b/services/inputflinger/include/PointerControllerInterface.h @@ -61,8 +61,6 @@ public: * TODO(b/293587049): Refactor the PointerController class into different controller types. */ enum class ControllerType { - // The PointerController that is responsible for drawing all icons. - LEGACY, // Represents a single mouse pointer. MOUSE, // Represents multiple touch spots. diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 9608210ca0..903c6ed9bc 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -402,10 +402,6 @@ void InputReader::refreshConfigurationLocked(ConfigurationChanges changes) { ALOGI("Reconfiguring input devices, changes=%s", changes.string().c_str()); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (changes.test(Change::DISPLAY_INFO)) { - updatePointerDisplayLocked(); - } - if (changes.test(Change::MUST_REOPEN)) { mEventHub->requestReopenDevices(); } else { @@ -490,47 +486,6 @@ bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, int32_t keyCode, int32 } } -std::shared_ptr<PointerControllerInterface> InputReader::getPointerControllerLocked( - int32_t deviceId) { - std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock(); - if (controller == nullptr) { - controller = mPolicy->obtainPointerController(deviceId); - mPointerController = controller; - updatePointerDisplayLocked(); - } - return controller; -} - -void InputReader::updatePointerDisplayLocked() { - std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock(); - if (controller == nullptr) { - return; - } - - std::optional<DisplayViewport> viewport = - mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId); - if (!viewport) { - ALOGW("Can't find the designated viewport with ID %" PRId32 " to update cursor input " - "mapper. Fall back to default display", - mConfig.defaultPointerDisplayId); - viewport = mConfig.getDisplayViewportById(ADISPLAY_ID_DEFAULT); - } - if (!viewport) { - ALOGE("Still can't find a viable viewport to update cursor input mapper. Skip setting it to" - " PointerController."); - return; - } - - controller->setDisplayViewport(*viewport); -} - -void InputReader::fadePointerLocked() { - std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock(); - if (controller != nullptr) { - controller->fade(PointerControllerInterface::Transition::GRADUAL); - } -} - void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { if (when < mNextTimeout) { mNextTimeout = when; @@ -1067,17 +1022,6 @@ bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, int32_t keyCode return mReader->shouldDropVirtualKeyLocked(now, keyCode, scanCode); } -void InputReader::ContextImpl::fadePointer() { - // lock is already held by the input loop - mReader->fadePointerLocked(); -} - -std::shared_ptr<PointerControllerInterface> InputReader::ContextImpl::getPointerController( - int32_t deviceId) { - // lock is already held by the input loop - return mReader->getPointerControllerLocked(deviceId); -} - void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { // lock is already held by the input loop mReader->requestTimeoutAtTimeLocked(when); diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 4c78db38cc..5f882cfcd3 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -16,7 +16,6 @@ #pragma once -#include <PointerControllerInterface.h> #include <android-base/thread_annotations.h> #include <utils/Condition.h> #include <utils/Mutex.h> @@ -141,9 +140,6 @@ protected: void disableVirtualKeysUntil(nsecs_t time) REQUIRES(mReader->mLock) override; bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) REQUIRES(mReader->mLock) override; - void fadePointer() REQUIRES(mReader->mLock) override; - std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) - REQUIRES(mReader->mLock) override; void requestTimeoutAtTime(nsecs_t when) REQUIRES(mReader->mLock) override; int32_t bumpGeneration() NO_THREAD_SAFETY_ANALYSIS override; void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) @@ -230,13 +226,6 @@ private: [[nodiscard]] std::list<NotifyArgs> dispatchExternalStylusStateLocked(const StylusState& state) REQUIRES(mLock); - // The PointerController that is shared among all the input devices that need it. - std::weak_ptr<PointerControllerInterface> mPointerController; - std::shared_ptr<PointerControllerInterface> getPointerControllerLocked(int32_t deviceId) - REQUIRES(mLock); - void updatePointerDisplayLocked() REQUIRES(mLock); - void fadePointerLocked() REQUIRES(mLock); - int32_t mGeneration GUARDED_BY(mLock); int32_t bumpGenerationLocked() REQUIRES(mLock); diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h index 69b2315a6c..907a49faa2 100644 --- a/services/inputflinger/reader/include/InputReaderContext.h +++ b/services/inputflinger/reader/include/InputReaderContext.h @@ -28,7 +28,6 @@ class InputDevice; class InputListenerInterface; class InputMapper; class InputReaderPolicyInterface; -class PointerControllerInterface; struct StylusState; /* Internal interface used by individual input devices to access global input device state @@ -45,9 +44,6 @@ public: virtual void disableVirtualKeysUntil(nsecs_t time) = 0; virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) = 0; - virtual void fadePointer() = 0; - virtual std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) = 0; - virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual int32_t bumpGeneration() = 0; diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index 738517b67e..658ceabcc3 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -483,16 +483,11 @@ std::list<NotifyArgs> KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) { void KeyboardInputMapper::onKeyDownProcessed(nsecs_t downTime) { InputReaderContext& context = *getContext(); context.setLastKeyDownTimestamp(downTime); - if (context.isPreventingTouchpadTaps()) { - // avoid pinging java service unnecessarily, just fade pointer again if it became visible - context.fadePointer(); - return; - } + // TODO(b/338652288): Move cursor fading logic into PointerChoreographer. // Ignore meta keys or multiple simultaneous down keys as they are likely to be keyboard // shortcuts bool shouldHideCursor = mKeyDowns.size() == 1 && !isMetaKey(mKeyDowns[0].keyCode); if (shouldHideCursor && context.getPolicy()->isInputMethodConnectionActive()) { - context.fadePointer(); context.setPreventingTouchpadTaps(true); } } diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index e9118a98c9..e2dcb41ac0 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -155,11 +155,6 @@ void FakeInputReaderPolicy::removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); } -void FakeInputReaderPolicy::setPointerController( - std::shared_ptr<FakePointerController> controller) { - mPointerController = std::move(controller); -} - const InputReaderConfiguration& FakeInputReaderPolicy::getReaderConfiguration() const { return mConfig; } @@ -183,10 +178,6 @@ PointerCaptureRequest FakeInputReaderPolicy::setPointerCapture(const sp<IBinder> return mConfig.pointerCaptureRequest; } -void FakeInputReaderPolicy::setShowTouches(bool enabled) { - mConfig.showTouches = enabled; -} - void FakeInputReaderPolicy::setDefaultPointerDisplayId(int32_t pointerDisplayId) { mConfig.defaultPointerDisplayId = pointerDisplayId; } @@ -228,11 +219,6 @@ void FakeInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* out *outConfig = mConfig; } -std::shared_ptr<PointerControllerInterface> FakeInputReaderPolicy::obtainPointerController( - int32_t /*deviceId*/) { - return mPointerController; -} - void FakeInputReaderPolicy::notifyInputDevicesChanged( const std::vector<InputDeviceInfo>& inputDevices) { std::scoped_lock lock(mLock); diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h index 710bb5496f..88f0ba7f9b 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -26,7 +26,6 @@ #include <InputDevice.h> #include <InputReaderBase.h> -#include "FakePointerController.h" #include "input/DisplayViewport.h" #include "input/InputDevice.h" @@ -62,14 +61,12 @@ public: const KeyboardLayoutInfo& layoutInfo); void addDisabledDevice(int32_t deviceId); void removeDisabledDevice(int32_t deviceId); - void setPointerController(std::shared_ptr<FakePointerController> controller); const InputReaderConfiguration& getReaderConfiguration() const; const std::vector<InputDeviceInfo> getInputDevices() const; TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor, ui::Rotation surfaceRotation); void setTouchAffineTransformation(const TouchAffineTransformation t); PointerCaptureRequest setPointerCapture(const sp<IBinder>& window); - void setShowTouches(bool enabled); void setDefaultPointerDisplayId(int32_t pointerDisplayId); void setPointerGestureEnabled(bool enabled); float getPointerGestureMovementSpeedRatio(); @@ -84,8 +81,6 @@ public: private: void getReaderConfiguration(InputReaderConfiguration* outConfig) override; - std::shared_ptr<PointerControllerInterface> obtainPointerController( - int32_t /*deviceId*/) override; void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override; std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override; @@ -97,7 +92,6 @@ private: std::condition_variable mDevicesChangedCondition; InputReaderConfiguration mConfig; - std::shared_ptr<FakePointerController> mPointerController; std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock); bool mInputDevicesChanged GUARDED_BY(mLock){false}; std::vector<DisplayViewport> mViewports; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bc173b16ce..09b358afe5 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -117,7 +117,7 @@ static constexpr gui::Uid SECONDARY_WINDOW_UID{1012}; // An arbitrary pid of the gesture monitor window static constexpr gui::Pid MONITOR_PID{2001}; -static constexpr int expectedWallpaperFlags = +static constexpr int EXPECTED_WALLPAPER_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID; @@ -827,7 +827,7 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance // Both foreground window and its wallpaper should receive the touch down foregroundWindow->consumeMotionDown(); - wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, @@ -837,13 +837,13 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; foregroundWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); - wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); // Now the foreground window goes away, but the wallpaper stays mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0}); foregroundWindow->consumeMotionCancel(); // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. - wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); } /** @@ -908,7 +908,7 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { // Both foreground window and its wallpaper should receive the touch down foregroundWindow->consumeMotionDown(); - wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, @@ -916,7 +916,7 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; foregroundWindow->consumeMotionMove(); - wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); // Wallpaper closes its channel, but the window remains. wallpaperWindow->destroyReceiver(); @@ -928,6 +928,301 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { foregroundWindow->consumeMotionCancel(); } +/** + * Two windows: left and right, and a separate wallpaper window underneath each. Device A sends a + * down event to the left window. Device B sends a down event to the right window. Next, the right + * window disappears. Both the right window and its wallpaper window should receive cancel event. + * The left window and its wallpaper window should not receive any events. + */ +TEST_F(InputDispatcherTest, MultiDeviceDisappearingWindowWithWallpaperWindows) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> leftForegroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window", + ADISPLAY_ID_DEFAULT); + leftForegroundWindow->setFrame(Rect(0, 0, 100, 100)); + leftForegroundWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> leftWallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window", + ADISPLAY_ID_DEFAULT); + leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100)); + leftWallpaperWindow->setIsWallpaper(true); + + sp<FakeWindowHandle> rightForegroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window", + ADISPLAY_ID_DEFAULT); + rightForegroundWindow->setFrame(Rect(100, 0, 200, 100)); + rightForegroundWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> rightWallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window", + ADISPLAY_ID_DEFAULT); + rightWallpaperWindow->setFrame(Rect(100, 0, 200, 100)); + rightWallpaperWindow->setIsWallpaper(true); + + mDispatcher->onWindowInfosChanged( + {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(), + *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()}, + {}, + 0, + 0}); + + const DeviceId deviceA = 9; + const DeviceId deviceB = 3; + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .deviceId(deviceA) + .build()); + leftForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); + leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithDeviceId(deviceA), + WithFlags(EXPECTED_WALLPAPER_FLAGS))); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) + .deviceId(deviceB) + .build()); + rightForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); + rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS))); + + // Now right foreground window disappears, but right wallpaper window remains. + mDispatcher->onWindowInfosChanged( + {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(), + *rightWallpaperWindow->getInfo()}, + {}, + 0, + 0}); + + // Left foreground window and left wallpaper window still exist, and should not receive any + // events. + leftForegroundWindow->assertNoEvents(); + leftWallpaperWindow->assertNoEvents(); + // Since right foreground window disappeared, right wallpaper window and right foreground window + // should receive cancel events. + rightForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB))); + rightWallpaperWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED))); +} + +/** + * Three windows arranged horizontally and without any overlap. Every window has a + * wallpaper window underneath. The middle window also has SLIPPERY flag. + * Device A sends a down event to the left window. Device B sends a down event to the middle window. + * Next, device B sends move event to the right window. Touch for device B should slip from the + * middle window to the right window. Also, the right wallpaper window should receive a down event. + * The middle window and its wallpaper window should receive a cancel event. The left window should + * not receive any events. If device B continues to report events, the right window and its + * wallpaper window should receive remaining events. + */ +TEST_F(InputDispatcherTest, MultiDeviceSlipperyTouchWithWallpaperWindow) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> leftForegroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window", + ADISPLAY_ID_DEFAULT); + leftForegroundWindow->setFrame(Rect(0, 0, 100, 100)); + leftForegroundWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> leftWallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window", + ADISPLAY_ID_DEFAULT); + leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100)); + leftWallpaperWindow->setIsWallpaper(true); + + sp<FakeWindowHandle> middleForegroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window", + ADISPLAY_ID_DEFAULT); + middleForegroundWindow->setFrame(Rect(100, 0, 200, 100)); + middleForegroundWindow->setDupTouchToWallpaper(true); + middleForegroundWindow->setSlippery(true); + sp<FakeWindowHandle> middleWallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window", + ADISPLAY_ID_DEFAULT); + middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100)); + middleWallpaperWindow->setIsWallpaper(true); + + sp<FakeWindowHandle> rightForegroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window", + ADISPLAY_ID_DEFAULT); + rightForegroundWindow->setFrame(Rect(200, 0, 300, 100)); + rightForegroundWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> rightWallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window", + ADISPLAY_ID_DEFAULT); + rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100)); + rightWallpaperWindow->setIsWallpaper(true); + + mDispatcher->onWindowInfosChanged( + {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(), + *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(), + *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()}, + {}, + 0, + 0}); + + const DeviceId deviceA = 9; + const DeviceId deviceB = 3; + // Device A sends a DOWN event to the left window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .deviceId(deviceA) + .build()); + leftForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); + leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithDeviceId(deviceA), + WithFlags(EXPECTED_WALLPAPER_FLAGS))); + // Device B sends a DOWN event to the middle window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) + .deviceId(deviceB) + .build()); + middleForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); + middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS))); + // Move the events of device B to the top of the right window. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(50)) + .deviceId(deviceB) + .build()); + middleForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB))); + middleWallpaperWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED))); + rightForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); + rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS))); + // Make sure the window on the right can receive the remaining events. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51)) + .deviceId(deviceB) + .build()); + leftForegroundWindow->assertNoEvents(); + leftWallpaperWindow->assertNoEvents(); + middleForegroundWindow->assertNoEvents(); + middleWallpaperWindow->assertNoEvents(); + rightForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB))); + rightWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), + WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS))); +} + +/** + * Similar to the test above, we have three windows, they are arranged horizontally and without any + * overlap, and every window has a wallpaper window. The middle window is a simple window, without + * any special flags. Device A reports a down event that lands in left window. Device B sends a down + * event to the middle window and then touch is transferred from the middle window to the right + * window. The right window and its wallpaper window should receive a down event. The middle window + * and its wallpaper window should receive a cancel event. The left window should not receive any + * events. Subsequent events reported by device B should go to the right window and its wallpaper. + */ +TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> leftForegroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left foreground window", + ADISPLAY_ID_DEFAULT); + leftForegroundWindow->setFrame(Rect(0, 0, 100, 100)); + leftForegroundWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> leftWallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left wallpaper window", + ADISPLAY_ID_DEFAULT); + leftWallpaperWindow->setFrame(Rect(0, 0, 100, 100)); + leftWallpaperWindow->setIsWallpaper(true); + + sp<FakeWindowHandle> middleForegroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Middle foreground window", + ADISPLAY_ID_DEFAULT); + middleForegroundWindow->setFrame(Rect(100, 0, 200, 100)); + middleForegroundWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> middleWallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Middle wallpaper window", + ADISPLAY_ID_DEFAULT); + middleWallpaperWindow->setFrame(Rect(100, 0, 200, 100)); + middleWallpaperWindow->setIsWallpaper(true); + + sp<FakeWindowHandle> rightForegroundWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right foreground window", + ADISPLAY_ID_DEFAULT); + rightForegroundWindow->setFrame(Rect(200, 0, 300, 100)); + rightForegroundWindow->setDupTouchToWallpaper(true); + sp<FakeWindowHandle> rightWallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right wallpaper window", + ADISPLAY_ID_DEFAULT); + rightWallpaperWindow->setFrame(Rect(200, 0, 300, 100)); + rightWallpaperWindow->setIsWallpaper(true); + + mDispatcher->onWindowInfosChanged( + {{*leftForegroundWindow->getInfo(), *leftWallpaperWindow->getInfo(), + *middleForegroundWindow->getInfo(), *middleWallpaperWindow->getInfo(), + *rightForegroundWindow->getInfo(), *rightWallpaperWindow->getInfo()}, + {}, + 0, + 0}); + + const DeviceId deviceA = 9; + const DeviceId deviceB = 3; + // Device A touch down on the left window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .deviceId(deviceA) + .build()); + leftForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA))); + leftWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithDeviceId(deviceA), + WithFlags(EXPECTED_WALLPAPER_FLAGS))); + // Device B touch down on the middle window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) + .deviceId(deviceB) + .build()); + middleForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB))); + middleWallpaperWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS))); + + // Transfer touch from the middle window to the right window. + ASSERT_TRUE(mDispatcher->transferTouchGesture(middleForegroundWindow->getToken(), + rightForegroundWindow->getToken())); + + middleForegroundWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB))); + middleWallpaperWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_CANCELED))); + rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), + WithDeviceId(deviceB), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); + rightWallpaperWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); + + // Make sure the right window can receive the remaining events. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(251).y(51)) + .deviceId(deviceB) + .build()); + leftForegroundWindow->assertNoEvents(); + leftWallpaperWindow->assertNoEvents(); + middleForegroundWindow->assertNoEvents(); + middleWallpaperWindow->assertNoEvents(); + rightForegroundWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), + WithDeviceId(deviceB), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); + rightWallpaperWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceB), + WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); +} + class ShouldSplitTouchFixture : public InputDispatcherTest, public ::testing::WithParamInterface<bool> {}; INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture, @@ -959,7 +1254,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { // Both top window and its wallpaper should receive the touch down foregroundWindow->consumeMotionDown(); - wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); // Second finger down on the top window const MotionEvent secondFingerDownEvent = @@ -975,7 +1270,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { foregroundWindow->consumeMotionPointerDown(/*pointerIndex=*/1); wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT, - expectedWallpaperFlags); + EXPECTED_WALLPAPER_FLAGS); const MotionEvent secondFingerUpEvent = MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) @@ -989,7 +1284,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; foregroundWindow->consumeMotionPointerUp(0); - wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, @@ -1004,7 +1299,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); - wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); } /** @@ -1046,7 +1341,7 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { // Both foreground window and its wallpaper should receive the touch down leftWindow->consumeMotionDown(); - wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); // Second finger down on the right window const MotionEvent secondFingerDownEvent = @@ -1064,14 +1359,14 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { // Since the touch is split, right window gets ACTION_DOWN rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); wallpaperWindow->consumeMotionPointerDown(/*pointerIndex=*/1, ADISPLAY_ID_DEFAULT, - expectedWallpaperFlags); + EXPECTED_WALLPAPER_FLAGS); // Now, leftWindow, which received the first finger, disappears. mDispatcher->onWindowInfosChanged( {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); leftWindow->consumeMotionCancel(); // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. - wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); // The pointer that's still down on the right window moves, and goes to the right window only. // As far as the dispatcher's concerned though, both pointers are still present. @@ -1126,7 +1421,7 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { // Both foreground window and its wallpaper should receive the touch down leftWindow->consumeMotionDown(); - wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); // Move to right window, the left window should receive cancel. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1136,7 +1431,7 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { leftWindow->consumeMotionCancel(); rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); - wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); } /** @@ -5763,7 +6058,7 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); - wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); // Dispatcher reports pointer down outside focus for the wallpaper mFakePolicy->assertOnPointerDownEquals(wallpaper->getToken()); @@ -5774,7 +6069,7 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { // The first window gets cancel and the second gets down firstWindow->consumeMotionCancel(); secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); - wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); // There should not be any changes to the focused window when transferring touch ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertOnPointerDownWasNotCalled()); @@ -5935,7 +6230,7 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); - wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); wallpaper2->assertNoEvents(); // Transfer touch focus to the second window @@ -5946,9 +6241,9 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { // The first window gets cancel and the second gets down firstWindow->consumeMotionCancel(); secondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); - wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, EXPECTED_WALLPAPER_FLAGS); wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT, - expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); + EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); // Send up event to the second window mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, @@ -5958,7 +6253,7 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { secondWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); wallpaper1->assertNoEvents(); wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT, - expectedWallpaperFlags | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); + EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); } // For the cases of single pointer touch and two pointers non-split touch, the api's diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index e1b46faac6..92489aec8d 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -46,7 +46,6 @@ #include <thread> #include "FakeEventHub.h" #include "FakeInputReaderPolicy.h" -#include "FakePointerController.h" #include "InputMapperTest.h" #include "InstrumentedInputReader.h" #include "TestConstants.h" @@ -1349,8 +1348,6 @@ protected: sp<FakeInputReaderPolicy> mFakePolicy; std::unique_ptr<InputReaderInterface> mReader; - std::shared_ptr<FakePointerController> mFakePointerController; - constexpr static auto EVENT_HAPPENED_TIMEOUT = 2000ms; constexpr static auto EVENT_DID_NOT_HAPPEN_TIMEOUT = 30ms; @@ -1359,8 +1356,6 @@ protected: GTEST_SKIP(); #endif mFakePolicy = sp<FakeInputReaderPolicy>::make(); - mFakePointerController = std::make_shared<FakePointerController>(); - mFakePolicy->setPointerController(mFakePointerController); setupInputReader(); } @@ -1654,8 +1649,6 @@ protected: } else { mFakePolicy->addInputUniqueIdAssociation(INPUT_PORT, UNIQUE_ID); } - mFakePointerController = std::make_shared<FakePointerController>(); - mFakePolicy->setPointerController(mFakePointerController); InputReaderIntegrationTest::setupInputReader(); diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h index db8916880a..6389cdc5fb 100644 --- a/services/inputflinger/tests/InterfaceMocks.h +++ b/services/inputflinger/tests/InterfaceMocks.h @@ -28,7 +28,6 @@ #include <EventHub.h> #include <InputReaderBase.h> #include <NotifyArgs.h> -#include <PointerControllerInterface.h> #include <StylusState.h> #include <VibrationElement.h> #include <android-base/logging.h> @@ -54,10 +53,6 @@ public: MOCK_METHOD(bool, shouldDropVirtualKey, (nsecs_t now, int32_t keyCode, int32_t scanCode), (override)); - MOCK_METHOD(void, fadePointer, (), (override)); - MOCK_METHOD(std::shared_ptr<PointerControllerInterface>, getPointerController, - (int32_t deviceId), (override)); - MOCK_METHOD(void, requestTimeoutAtTime, (nsecs_t when), (override)); int32_t bumpGeneration() override { return ++mGeneration; } diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp index b44529bd04..031b77d67a 100644 --- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp +++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp @@ -72,8 +72,6 @@ protected: } void testPointerVisibilityForKeys(const std::vector<int32_t>& keyCodes, bool expectVisible) { - EXPECT_CALL(mMockInputReaderContext, fadePointer) - .Times(expectVisible ? 0 : keyCodes.size()); for (int32_t keyCode : keyCodes) { process(EV_KEY, keyCode, 1); process(EV_SYN, SYN_REPORT, 0); @@ -84,7 +82,6 @@ protected: void testTouchpadTapStateForKeys(const std::vector<int32_t>& keyCodes, const bool expectPrevent) { - EXPECT_CALL(mMockInputReaderContext, isPreventingTouchpadTaps).Times(keyCodes.size()); if (expectPrevent) { EXPECT_CALL(mMockInputReaderContext, setPreventingTouchpadTaps(true)) .Times(keyCodes.size()); diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 2602ebbd14..e020ca9d62 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -258,57 +258,16 @@ public: void sysfsNodeChanged(const std::string& sysfsNodePath) override {} }; -class FuzzPointerController : public PointerControllerInterface { - std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp; - -public: - FuzzPointerController(std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp) : mFdp(mFdp) {} - ~FuzzPointerController() {} - std::optional<FloatRect> getBounds() const override { - if (mFdp->ConsumeBool()) { - return {}; - } else { - return FloatRect{mFdp->ConsumeFloatingPoint<float>(), - mFdp->ConsumeFloatingPoint<float>(), - mFdp->ConsumeFloatingPoint<float>(), - mFdp->ConsumeFloatingPoint<float>()}; - } - } - void move(float deltaX, float deltaY) override {} - void setPosition(float x, float y) override {} - FloatPoint getPosition() const override { - return {mFdp->ConsumeFloatingPoint<float>(), mFdp->ConsumeFloatingPoint<float>()}; - } - void fade(Transition transition) override {} - void unfade(Transition transition) override {} - void setPresentation(Presentation presentation) override {} - void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits, int32_t displayId) override {} - void clearSpots() override {} - int32_t getDisplayId() const override { return mFdp->ConsumeIntegral<int32_t>(); } - void setDisplayViewport(const DisplayViewport& displayViewport) override {} - void updatePointerIcon(PointerIconStyle iconId) override {} - void setCustomPointerIcon(const SpriteIcon& icon) override {} - void setSkipScreenshot(int32_t displayId, bool skip) override{}; - std::string dump() override { return ""; } -}; - class FuzzInputReaderPolicy : public InputReaderPolicyInterface { TouchAffineTransformation mTransform; - std::shared_ptr<FuzzPointerController> mPointerController; std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp; protected: ~FuzzInputReaderPolicy() {} public: - FuzzInputReaderPolicy(std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp) : mFdp(mFdp) { - mPointerController = std::make_shared<FuzzPointerController>(mFdp); - } + FuzzInputReaderPolicy(std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp) : mFdp(mFdp) {} void getReaderConfiguration(InputReaderConfiguration* outConfig) override {} - std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override { - return mPointerController; - } void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {} std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier& identifier, @@ -360,10 +319,6 @@ public: bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override { return mFdp->ConsumeBool(); } - void fadePointer() override {} - std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) override { - return mPolicy->obtainPointerController(0); - } void requestTimeoutAtTime(nsecs_t when) override {} int32_t bumpGeneration() override { return mFdp->ConsumeIntegral<int32_t>(); } void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override {} diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 935346712f..a4c75a44ce 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -448,6 +448,7 @@ public: void commitTransactionsLocked(uint32_t transactionFlags) { Mutex::Autolock lock(mFlinger->mStateLock); ftl::FakeGuard guard(kMainThreadContext); + mFlinger->processDisplayChangesLocked(); mFlinger->commitTransactionsLocked(transactionFlags); } |