Merge "Refactor RenderAreaFuture to use RenderAreaBuilder" into main
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 01f523b..bec3283 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 @@
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 @@
__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 @@
__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 @@
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 6a02916..d80a366 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -182,23 +182,27 @@
* 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 @@
* 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/include/ftl/details/hash.h b/include/ftl/details/hash.h
index f9a7fa8..230ae51 100644
--- a/include/ftl/details/hash.h
+++ b/include/ftl/details/hash.h
@@ -43,6 +43,7 @@
return v ^ (v >> 47);
}
+__attribute__((no_sanitize("unsigned-integer-overflow")))
constexpr std::uint64_t hash_length_16(std::uint64_t u, std::uint64_t v) {
constexpr std::uint64_t kPrime = 0x9ddfea08eb382d69ull;
auto a = (u ^ v) * kPrime;
@@ -58,6 +59,7 @@
constexpr std::uint64_t kPrime2 = 0x9ae16a3b2f90404full;
constexpr std::uint64_t kPrime3 = 0xc949d7c7509e6557ull;
+__attribute__((no_sanitize("unsigned-integer-overflow")))
inline std::uint64_t hash_length_0_to_16(const char* str, std::uint64_t length) {
if (length > 8) {
const auto a = read_unaligned(str);
@@ -80,6 +82,7 @@
return kPrime2;
}
+__attribute__((no_sanitize("unsigned-integer-overflow")))
inline std::uint64_t hash_length_17_to_32(const char* str, std::uint64_t length) {
const auto a = read_unaligned(str) * kPrime1;
const auto b = read_unaligned(str + 8);
@@ -89,6 +92,7 @@
a + rotate(b ^ kPrime3, 20) - c + length);
}
+__attribute__((no_sanitize("unsigned-integer-overflow")))
inline std::uint64_t hash_length_33_to_64(const char* str, std::uint64_t length) {
auto z = read_unaligned(str + 24);
auto a = read_unaligned(str) + (length + read_unaligned(str + length - 16)) * kPrime0;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 6ccc6ca..81f6a58 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -40,6 +40,9 @@
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 @@
// 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/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 4dc2737..a3d0c2b 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -17,7 +17,12 @@
#define LOG_TAG "PointerChoreographer"
#include <android-base/logging.h>
+#include <com_android_input_flags.h>
+#if defined(__ANDROID__)
+#include <gui/SurfaceComposerClient.h>
+#endif
#include <input/PrintTools.h>
+#include <unordered_set>
#include "PointerChoreographer.h"
@@ -25,6 +30,10 @@
namespace android {
+namespace input_flags = com::android::input::flags;
+static const bool HIDE_TOUCH_INDICATORS_FOR_SECURE_WINDOWS =
+ input_flags::hide_pointer_indicators_for_secure_windows();
+
namespace {
bool isFromMouse(const NotifyMotionArgs& args) {
@@ -96,6 +105,14 @@
mShowTouchesEnabled(false),
mStylusPointerIconEnabled(false) {}
+PointerChoreographer::~PointerChoreographer() {
+ std::scoped_lock _l(mLock);
+ if (mWindowInfoListener == nullptr) {
+ return;
+ }
+ mWindowInfoListener->onPointerChoreographerDestroyed();
+}
+
void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
PointerDisplayChange pointerDisplayChange;
@@ -231,6 +248,7 @@
auto [it, _] = mDrawingTabletPointersByDevice.try_emplace(args.deviceId,
getMouseControllerConstructor(
args.displayId));
+ // TODO (b/325252005): Add handing for drawing tablets mouse pointer controller
PointerControllerInterface& pc = *it->second;
@@ -268,7 +286,11 @@
}
// Get the touch pointer controller for the device, or create one if it doesn't exist.
- auto [it, _] = mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
+ auto [it, controllerAdded] =
+ mTouchPointersByDevice.try_emplace(args.deviceId, mTouchControllerConstructor);
+ if (controllerAdded) {
+ onControllerAddedOrRemoved();
+ }
PointerControllerInterface& pc = *it->second;
@@ -306,6 +328,7 @@
auto [it, _] =
mStylusPointersByDevice.try_emplace(args.deviceId,
getStylusControllerConstructor(args.displayId));
+ // TODO (b/325252005): Add handing for stylus pointer controller
PointerControllerInterface& pc = *it->second;
@@ -345,6 +368,31 @@
mTouchPointersByDevice.erase(args.deviceId);
mStylusPointersByDevice.erase(args.deviceId);
mDrawingTabletPointersByDevice.erase(args.deviceId);
+ onControllerAddedOrRemoved();
+}
+
+void PointerChoreographer::onControllerAddedOrRemoved() {
+ if (!HIDE_TOUCH_INDICATORS_FOR_SECURE_WINDOWS) {
+ return;
+ }
+ bool requireListener = !mTouchPointersByDevice.empty();
+ // TODO (b/325252005): Update for other types of pointer controllers
+
+ if (requireListener && mWindowInfoListener == nullptr) {
+ mWindowInfoListener = sp<PointerChoreographerDisplayInfoListener>::make(this);
+ auto initialInfo = std::make_pair(std::vector<android::gui::WindowInfo>{},
+ std::vector<android::gui::DisplayInfo>{});
+#if defined(__ANDROID__)
+ SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener,
+ &initialInfo);
+#endif
+ onWindowInfosChangedLocked(initialInfo.first);
+ } else if (!requireListener && mWindowInfoListener != nullptr) {
+#if defined(__ANDROID__)
+ SurfaceComposerClient::getDefault()->removeWindowInfosListener(mWindowInfoListener);
+#endif
+ mWindowInfoListener = nullptr;
+ }
}
void PointerChoreographer::notifyPointerCaptureChanged(
@@ -358,6 +406,12 @@
mNextListener.notify(args);
}
+void PointerChoreographer::onWindowInfosChanged(
+ const std::vector<android::gui::WindowInfo>& windowInfos) {
+ std::scoped_lock _l(mLock);
+ onWindowInfosChangedLocked(windowInfos);
+}
+
void PointerChoreographer::dump(std::string& dump) {
std::scoped_lock _l(mLock);
@@ -410,6 +464,7 @@
if (it == mMousePointersByDisplay.end()) {
it = mMousePointersByDisplay.emplace(displayId, getMouseControllerConstructor(displayId))
.first;
+ // TODO (b/325252005): Add handing for mouse pointer controller
}
return {displayId, *it->second};
@@ -450,6 +505,8 @@
auto [mousePointerIt, isNewMousePointer] =
mMousePointersByDisplay.try_emplace(displayId,
getMouseControllerConstructor(displayId));
+ // TODO (b/325252005): Add handing for mouse pointer controller
+
mMouseDevices.emplace(info.getId());
if ((!isKnownMouse || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
@@ -488,6 +545,8 @@
mInputDeviceInfos.end();
});
+ onControllerAddedOrRemoved();
+
// Check if we need to notify the policy if there's a change on the pointer display ID.
return calculatePointerDisplayChangeToNotify();
}
@@ -652,6 +711,31 @@
return false;
}
+void PointerChoreographer::onWindowInfosChangedLocked(
+ const std::vector<android::gui::WindowInfo>& windowInfos) {
+ // Mark all spot controllers secure on displays containing secure windows and
+ // remove secure flag from others if required
+ std::unordered_set<int32_t> privacySensitiveDisplays;
+ std::unordered_set<int32_t> allDisplayIds;
+ for (const auto& windowInfo : windowInfos) {
+ allDisplayIds.insert(windowInfo.displayId);
+ if (!windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE) &&
+ windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY)) {
+ privacySensitiveDisplays.insert(windowInfo.displayId);
+ }
+ }
+
+ for (auto& it : mTouchPointersByDevice) {
+ auto& pc = it.second;
+ for (int32_t displayId : allDisplayIds) {
+ pc->setSkipScreenshot(displayId,
+ privacySensitiveDisplays.find(displayId) !=
+ privacySensitiveDisplays.end());
+ }
+ }
+ // TODO (b/325252005): update skip screenshot flag for other types of pointer controllers
+}
+
void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) {
std::scoped_lock lock(mLock);
if (visible) {
@@ -702,4 +786,18 @@
return ConstructorDelegate(std::move(ctor));
}
+void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfosChanged(
+ const gui::WindowInfosUpdate& windowInfosUpdate) {
+ std::scoped_lock _l(mListenerLock);
+ if (mPointerChoreographer != nullptr) {
+ mPointerChoreographer->onWindowInfosChanged(windowInfosUpdate.windowInfos);
+ }
+}
+
+void PointerChoreographer::PointerChoreographerDisplayInfoListener::
+ onPointerChoreographerDestroyed() {
+ std::scoped_lock _l(mListenerLock);
+ mPointerChoreographer = nullptr;
+}
+
} // namespace android
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
index a3c210e..b29d9cd 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -21,6 +21,7 @@
#include "PointerChoreographerPolicyInterface.h"
#include <android-base/thread_annotations.h>
+#include <gui/WindowInfosListener.h>
#include <type_traits>
namespace android {
@@ -83,7 +84,7 @@
public:
explicit PointerChoreographer(InputListenerInterface& listener,
PointerChoreographerPolicyInterface&);
- ~PointerChoreographer() override = default;
+ ~PointerChoreographer() override;
void setDefaultMouseDisplayId(int32_t displayId) override;
void setDisplayViewports(const std::vector<DisplayViewport>& viewports) override;
@@ -106,6 +107,9 @@
void notifyDeviceReset(const NotifyDeviceResetArgs& args) override;
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override;
+ // Public because it's also used by tests to simulate the WindowInfosListener callback
+ void onWindowInfosChanged(const std::vector<android::gui::WindowInfo>& windowInfos);
+
void dump(std::string& dump) override;
private:
@@ -127,6 +131,22 @@
void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
void processDeviceReset(const NotifyDeviceResetArgs& args);
+ void onControllerAddedOrRemoved() REQUIRES(mLock);
+ void onWindowInfosChangedLocked(const std::vector<android::gui::WindowInfo>& windowInfos)
+ REQUIRES(mLock);
+
+ class PointerChoreographerDisplayInfoListener : public gui::WindowInfosListener {
+ public:
+ explicit PointerChoreographerDisplayInfoListener(PointerChoreographer* pc)
+ : mPointerChoreographer(pc){};
+ void onWindowInfosChanged(const gui::WindowInfosUpdate&) override;
+ void onPointerChoreographerDestroyed();
+
+ private:
+ std::mutex mListenerLock;
+ PointerChoreographer* mPointerChoreographer GUARDED_BY(mListenerLock);
+ };
+ sp<PointerChoreographerDisplayInfoListener> mWindowInfoListener GUARDED_BY(mLock);
using ControllerConstructor =
ConstructorDelegate<std::function<std::shared_ptr<PointerControllerInterface>()>>;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index de841ba..79b8560 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -5363,31 +5363,32 @@
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 @@
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 @@
"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::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 @@
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::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 @@
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 3579a67..3d127c2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -701,14 +701,14 @@
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 296c334..0c9ad3c 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -211,9 +211,11 @@
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 9ddb4e2..9d4bb3d 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -66,7 +66,7 @@
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 77e672c..4d8ed99 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -61,9 +61,6 @@
// 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 @@
// 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 @@
pointerGestureSwipeMaxWidthRatio(0.25f),
pointerGestureMovementSpeedRatio(0.8f),
pointerGestureZoomSpeedRatio(0.3f),
- showTouches(false),
pointerCaptureRequest(),
touchpadPointerSpeed(0),
touchpadNaturalScrollingEnabled(true),
@@ -449,10 +442,6 @@
/* 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 c44486f..c1467b3 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -61,8 +61,6 @@
* 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.
@@ -143,6 +141,11 @@
/* Sets the custom pointer icon for mice or styluses. */
virtual void setCustomPointerIcon(const SpriteIcon& icon) = 0;
+
+ /* Sets the flag to skip screenshot of the pointer indicators on the display matching the
+ * provided displayId.
+ */
+ virtual void setSkipScreenshot(int32_t displayId, bool skip) = 0;
};
} // namespace android
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 9608210..903c6ed 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -402,10 +402,6 @@
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 @@
}
}
-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 @@
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 4c78db3..5f882cf 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 @@
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 @@
[[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 69b2315..907a49f 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -28,7 +28,6 @@
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 @@
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 738517b..658ceab 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -483,16 +483,11 @@
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 e9118a9..e2dcb41 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -155,11 +155,6 @@
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 @@
return mConfig.pointerCaptureRequest;
}
-void FakeInputReaderPolicy::setShowTouches(bool enabled) {
- mConfig.showTouches = enabled;
-}
-
void FakeInputReaderPolicy::setDefaultPointerDisplayId(int32_t pointerDisplayId) {
mConfig.defaultPointerDisplayId = pointerDisplayId;
}
@@ -228,11 +219,6 @@
*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 710bb54..88f0ba7 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 @@
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 @@
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 @@
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/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp
index dc199e2..28d4b67 100644
--- a/services/inputflinger/tests/FakePointerController.cpp
+++ b/services/inputflinger/tests/FakePointerController.cpp
@@ -76,6 +76,14 @@
mCustomIconStyle = icon.style;
}
+void FakePointerController::setSkipScreenshot(int32_t displayId, bool skip) {
+ if (skip) {
+ mDisplaysToSkipScreenshot.insert(displayId);
+ } else {
+ mDisplaysToSkipScreenshot.erase(displayId);
+ }
+};
+
void FakePointerController::assertViewportSet(int32_t displayId) {
ASSERT_TRUE(mDisplayId);
ASSERT_EQ(displayId, mDisplayId);
@@ -117,6 +125,14 @@
ASSERT_EQ(std::nullopt, mCustomIconStyle);
}
+void FakePointerController::assertIsHiddenOnMirroredDisplays(int32_t displayId, bool isHidden) {
+ if (isHidden) {
+ ASSERT_TRUE(mDisplaysToSkipScreenshot.find(displayId) != mDisplaysToSkipScreenshot.end());
+ } else {
+ ASSERT_TRUE(mDisplaysToSkipScreenshot.find(displayId) == mDisplaysToSkipScreenshot.end());
+ }
+}
+
bool FakePointerController::isPointerShown() {
return mIsPointerShown;
}
diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h
index 536b447..b5b982e 100644
--- a/services/inputflinger/tests/FakePointerController.h
+++ b/services/inputflinger/tests/FakePointerController.h
@@ -21,6 +21,7 @@
#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <utils/BitSet.h>
+#include <unordered_set>
namespace android {
@@ -45,6 +46,7 @@
void setDisplayViewport(const DisplayViewport& viewport) override;
void updatePointerIcon(PointerIconStyle iconId) override;
void setCustomPointerIcon(const SpriteIcon& icon) override;
+ void setSkipScreenshot(int32_t displayId, bool skip) override;
void fade(Transition) override;
void assertViewportSet(int32_t displayId);
@@ -55,6 +57,7 @@
void assertPointerIconNotSet();
void assertCustomPointerIconSet(PointerIconStyle iconId);
void assertCustomPointerIconNotSet();
+ void assertIsHiddenOnMirroredDisplays(int32_t displayId, bool isHidden);
bool isPointerShown();
private:
@@ -77,6 +80,7 @@
std::optional<PointerIconStyle> mCustomIconStyle;
std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
+ std::unordered_set<int32_t> mDisplaysToSkipScreenshot;
};
} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index bc173b1..09b358a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -117,7 +117,7 @@
// 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 @@
// 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 @@
<< "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 @@
// 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 @@
<< "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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 e1b46fa..92489ae 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 @@
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 @@
GTEST_SKIP();
#endif
mFakePolicy = sp<FakeInputReaderPolicy>::make();
- mFakePointerController = std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(mFakePointerController);
setupInputReader();
}
@@ -1654,8 +1649,6 @@
} 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 db89168..6389cdc 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 @@
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 b44529b..031b77d 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -72,8 +72,6 @@
}
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 @@
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/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 11c6b7e..d81f8a0 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -15,7 +15,8 @@
*/
#include "../PointerChoreographer.h"
-
+#include <com_android_input_flags.h>
+#include <flag_macros.h>
#include <gtest/gtest.h>
#include <deque>
#include <vector>
@@ -27,6 +28,8 @@
namespace android {
+namespace input_flags = com::android::input::flags;
+
using ControllerType = PointerControllerInterface::ControllerType;
using testing::AllOf;
@@ -1587,6 +1590,76 @@
firstMousePc->assertPointerIconNotSet();
}
+TEST_F_WITH_FLAGS(PointerChoreographerTest, HidesTouchSpotsOnMirroredDisplaysForSecureWindow,
+ REQUIRES_FLAGS_ENABLED(
+ ACONFIG_FLAG(input_flags, hide_pointer_indicators_for_secure_windows))) {
+ // Add a touch device and enable show touches.
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
+ mChoreographer.setShowTouchesEnabled(true);
+
+ // Emit touch events to create PointerController
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(FIRST_TOUCH_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+
+ // By default touch indicators should not be hidden
+ auto pc = assertPointerControllerCreated(ControllerType::TOUCH);
+ pc->assertIsHiddenOnMirroredDisplays(DISPLAY_ID, /*isHidden=*/false);
+ pc->assertIsHiddenOnMirroredDisplays(ANOTHER_DISPLAY_ID, /*isHidden=*/false);
+
+ // adding secure window on display should set flag to hide pointer indicators on corresponding
+ // mirrored display
+ gui::WindowInfo windowInfo;
+ windowInfo.displayId = DISPLAY_ID;
+ windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY;
+ mChoreographer.onWindowInfosChanged({windowInfo});
+ pc->assertIsHiddenOnMirroredDisplays(DISPLAY_ID, /*isHidden=*/true);
+ pc->assertIsHiddenOnMirroredDisplays(ANOTHER_DISPLAY_ID, /*isHidden=*/false);
+
+ // removing the secure window should reset the state
+ windowInfo.inputConfig.clear(gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY);
+ mChoreographer.onWindowInfosChanged({windowInfo});
+ pc->assertIsHiddenOnMirroredDisplays(DISPLAY_ID, /*isHidden=*/false);
+ pc->assertIsHiddenOnMirroredDisplays(ANOTHER_DISPLAY_ID, /*isHidden=*/false);
+}
+
+TEST_F_WITH_FLAGS(PointerChoreographerTest,
+ DoesNotHidesTouchSpotsOnMirroredDisplaysForInvisibleWindow,
+ REQUIRES_FLAGS_ENABLED(
+ ACONFIG_FLAG(input_flags, hide_pointer_indicators_for_secure_windows))) {
+ // Add a touch device and enable show touches.
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
+ mChoreographer.setShowTouchesEnabled(true);
+
+ // Emit touch events to create PointerController
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(FIRST_TOUCH_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+
+ // By default touch indicators should not be hidden
+ auto pc = assertPointerControllerCreated(ControllerType::TOUCH);
+ pc->assertIsHiddenOnMirroredDisplays(DISPLAY_ID, /*isHidden=*/false);
+ pc->assertIsHiddenOnMirroredDisplays(ANOTHER_DISPLAY_ID, /*isHidden=*/false);
+
+ // adding secure but hidden window on display should still not set flag to hide pointer
+ // indicators
+ gui::WindowInfo windowInfo;
+ windowInfo.displayId = DISPLAY_ID;
+ windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY;
+ windowInfo.inputConfig |= gui::WindowInfo::InputConfig::NOT_VISIBLE;
+ mChoreographer.onWindowInfosChanged({windowInfo});
+ pc->assertIsHiddenOnMirroredDisplays(DISPLAY_ID, /*isHidden=*/false);
+ pc->assertIsHiddenOnMirroredDisplays(ANOTHER_DISPLAY_ID, /*isHidden=*/false);
+}
+
TEST_P(StylusTestFixture, SetsPointerIconForStylus) {
const auto& [name, source, controllerType] = GetParam();
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 7898126..e020ca9 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -258,56 +258,16 @@
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 {}
- 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,
@@ -359,10 +319,6 @@
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/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index ccb3aa7..ccaa05f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -346,7 +346,9 @@
// Used to skip event dispatch before EventThread creation during boot.
// TODO: b/241285191 - Reorder Scheduler initialization to avoid this.
bool hasEventThreads() const {
- return CC_LIKELY(mRenderEventThread && mLastCompositeEventThread);
+ return CC_LIKELY(
+ mRenderEventThread &&
+ (FlagManager::getInstance().deprecate_vsync_sf() || mLastCompositeEventThread));
}
EventThread& eventThreadFor(Cycle cycle) const {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0369549..0d2e514 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -425,7 +425,8 @@
mInternalDisplayDensity(
getDensityFromProperty("ro.sf.lcd_density", !mEmulatedDisplayDensity)),
mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
- mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make()) {
+ mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make()),
+ mSkipPowerOnForQuiescent(base::GetBoolProperty("ro.boot.quiescent"s, false)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
}
@@ -3883,7 +3884,9 @@
if (currentState.physical) {
const auto display = getDisplayDeviceLocked(displayToken);
- setPowerModeInternal(display, hal::PowerMode::ON);
+ if (!mSkipPowerOnForQuiescent) {
+ setPowerModeInternal(display, hal::PowerMode::ON);
+ }
// TODO(b/175678251) Call a listener instead.
if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) {
@@ -6102,8 +6105,11 @@
// Power on all displays. The primary display is first, so becomes the active display. Also,
// the DisplayCapability set of a display is populated on its first powering on. Do this now
// before responding to any Binder query from DisplayManager about display capabilities.
- for (const auto& [id, display] : mPhysicalDisplays) {
- setPowerModeInternal(getDisplayDeviceLocked(id), hal::PowerMode::ON);
+ // Additionally, do not turn on displays if the boot should be quiescent.
+ if (!mSkipPowerOnForQuiescent) {
+ for (const auto& [id, display] : mPhysicalDisplays) {
+ setPowerModeInternal(getDisplayDeviceLocked(id), hal::PowerMode::ON);
+ }
}
}
}
@@ -6262,6 +6268,7 @@
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
auto future = mScheduler->schedule([=, this]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(
kMainThreadContext) {
+ mSkipPowerOnForQuiescent = false;
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index af8f315..4cb5aa3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1494,6 +1494,8 @@
bool mPowerHintSessionEnabled;
bool mLayerLifecycleManagerEnabled = false;
+ // Whether a display should be turned on when initialized
+ bool mSkipPowerOnForQuiescent;
frontend::LayerLifecycleManager mLayerLifecycleManager GUARDED_BY(kMainThreadContext);
frontend::LayerHierarchyBuilder mLayerHierarchyBuilder GUARDED_BY(kMainThreadContext);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d3b6e17..a0c1372 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -448,6 +448,7 @@
void commitTransactionsLocked(uint32_t transactionFlags) {
Mutex::Autolock lock(mFlinger->mStateLock);
ftl::FakeGuard guard(kMainThreadContext);
+ mFlinger->processDisplayChangesLocked();
mFlinger->commitTransactionsLocked(transactionFlags);
}