(touch-mode-md 2/n) Add md touch mode support in InputDispatcher
Major changes in this CL:
* Drop kPerDisplayTouchModeEnabled (keep the native layer simple);
* Include display id in TouchModeEntry;
* Cache touch mode state per display id.
Bug: 198499018
Test: atest inputflinger_tests
Change-Id: Idc800e08bfca1c19342ad34865bd6c9e5dc6a7d3
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 12eeea6..3d4dd7e 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -112,8 +112,6 @@
void notifyDropWindow(const sp<IBinder>&, float x, float y) override {}
- bool isPerDisplayTouchModeEnabled() override { return false; }
-
InputDispatcherConfiguration mConfig;
};
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 8046bbe..33e7e17 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -195,9 +195,10 @@
// --- TouchModeEntry ---
-TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode)
+TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int displayId)
: EventEntry(id, Type::TOUCH_MODE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER),
- inTouchMode(inTouchMode) {}
+ inTouchMode(inTouchMode),
+ displayId(displayId) {}
TouchModeEntry::~TouchModeEntry() {}
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 1f916f3..60f319a 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -210,8 +210,9 @@
struct TouchModeEntry : EventEntry {
bool inTouchMode;
+ int32_t displayId;
- TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode);
+ TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int32_t displayId);
std::string getDescription() const override;
~TouchModeEntry() override;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ff63a6f..399153c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -544,17 +544,12 @@
mDispatchEnabled(false),
mDispatchFrozen(false),
mInputFilterEnabled(false),
- // mInTouchMode will be initialized by the WindowManager to the default device config.
- // To avoid leaking stack in case that call never comes, and for tests,
- // initialize it here anyways.
- mInTouchMode(kDefaultInTouchMode),
mMaximumObscuringOpacityForTouch(1.0f),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
mStaleEventTimeout(staleEventTimeout),
mLatencyAggregator(),
- mLatencyTracker(&mLatencyAggregator),
- kPerDisplayTouchModeEnabled(mPolicy->isPerDisplayTouchModeEnabled()) {
+ mLatencyTracker(&mLatencyAggregator) {
mLooper = sp<Looper>::make(false);
mReporter = createInputReporter();
@@ -562,7 +557,6 @@
SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
mKeyRepeatState.lastKeyEntry = nullptr;
-
policy->getDispatcherConfiguration(&mConfig);
}
@@ -1435,7 +1429,7 @@
void InputDispatcher::dispatchTouchModeChangeLocked(nsecs_t currentTime,
const std::shared_ptr<TouchModeEntry>& entry) {
const std::vector<sp<WindowInfoHandle>>& windowHandles =
- getWindowHandlesLocked(mFocusedDisplayId);
+ getWindowHandlesLocked(entry->displayId);
if (windowHandles.empty()) {
return;
}
@@ -1452,7 +1446,6 @@
const std::vector<sp<WindowInfoHandle>>& windowHandles) const {
std::vector<InputTarget> inputTargets;
for (const sp<WindowInfoHandle>& handle : windowHandles) {
- // TODO(b/193718270): Due to performance concerns, consider notifying visible windows only.
const sp<IBinder>& token = handle->getToken();
if (token == nullptr) {
continue;
@@ -5012,15 +5005,20 @@
bool needWake = false;
{
std::scoped_lock lock(mLock);
- if (mInTouchMode == inTouchMode) {
+ ALOGD_IF(DEBUG_TOUCH_MODE,
+ "Request to change touch mode to %s (calling pid=%d, uid=%d, "
+ "hasPermission=%s, target displayId=%d, mTouchModePerDisplay[displayId]=%s)",
+ toString(inTouchMode), pid, uid, toString(hasPermission), displayId,
+ mTouchModePerDisplay.count(displayId) == 0
+ ? "not set"
+ : std::to_string(mTouchModePerDisplay[displayId]).c_str());
+
+ // TODO(b/198499018): Ensure that WM can guarantee that touch mode is properly set when
+ // display is created.
+ auto touchModeIt = mTouchModePerDisplay.find(displayId);
+ if (touchModeIt != mTouchModePerDisplay.end() && touchModeIt->second == inTouchMode) {
return false;
}
- if (DEBUG_TOUCH_MODE) {
- ALOGD("Request to change touch mode from %s to %s (calling pid=%d, uid=%d, "
- "hasPermission=%s, target displayId=%d, perDisplayTouchModeEnabled=%s)",
- toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission),
- displayId, toString(kPerDisplayTouchModeEnabled));
- }
if (!hasPermission) {
if (!focusedWindowIsOwnedByLocked(pid, uid) &&
!recentWindowsAreOwnedByLocked(pid, uid)) {
@@ -5030,11 +5028,9 @@
return false;
}
}
-
- // TODO(b/198499018): Store touch mode per display (kPerDisplayTouchModeEnabled)
- mInTouchMode = inTouchMode;
-
- auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode);
+ mTouchModePerDisplay[displayId] = inTouchMode;
+ auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode,
+ displayId);
needWake = enqueueInboundEventLocked(std::move(entry));
} // release lock
@@ -5474,6 +5470,16 @@
dump += INDENT "AppSwitch: not pending\n";
}
+ if (!mTouchModePerDisplay.empty()) {
+ dump += INDENT "TouchModePerDisplay:\n";
+ for (const auto& [displayId, touchMode] : mTouchModePerDisplay) {
+ dump += StringPrintf(INDENT2 "Display: %" PRId32 " TouchMode: %s\n", displayId,
+ std::to_string(touchMode).c_str());
+ }
+ } else {
+ dump += INDENT "TouchModePerDisplay: <none>\n";
+ }
+
dump += INDENT "Configuration:\n";
dump += StringPrintf(INDENT2 "KeyRepeatDelay: %" PRId64 "ms\n", ns2ms(mConfig.keyRepeatDelay));
dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %" PRId64 "ms\n",
@@ -6366,6 +6372,8 @@
mFocusResolver.displayRemoved(displayId);
// Reset pointer capture eligibility, regardless of previous state.
std::erase(mIneligibleDisplaysForPointerCapture, displayId);
+ // Remove the associated touch mode state.
+ mTouchModePerDisplay.erase(displayId);
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index b5bbce8..f6872d1 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -343,9 +343,13 @@
bool mDispatchEnabled GUARDED_BY(mLock);
bool mDispatchFrozen GUARDED_BY(mLock);
bool mInputFilterEnabled GUARDED_BY(mLock);
- bool mInTouchMode GUARDED_BY(mLock);
float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock);
+ // This map is not really needed, but it helps a lot with debugging (dumpsys input).
+ // In the java layer, touch mode states are spread across multiple DisplayContent objects,
+ // making harder to snapshot and retrieve them.
+ std::map<int32_t /*displayId*/, bool /*inTouchMode*/> mTouchModePerDisplay GUARDED_BY(mLock);
+
class DispatcherWindowListener : public gui::WindowInfosListener {
public:
explicit DispatcherWindowListener(InputDispatcher& dispatcher) : mDispatcher(dispatcher){};
@@ -384,7 +388,7 @@
bool hasResponsiveConnectionLocked(android::gui::WindowInfoHandle& windowHandle) const
REQUIRES(mLock);
- // Gets all the input targets (with their respective input channels) from the window handles
+ // Returns all the input targets (with their respective input channels) from the window handles
// passed as argument.
std::vector<InputTarget> getInputTargetsFromWindowHandlesLocked(
const std::vector<sp<android::gui::WindowInfoHandle>>& windowHandles) const
@@ -685,9 +689,6 @@
bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
- // Per display touch mode enabled
- const bool kPerDisplayTouchModeEnabled;
-
sp<InputReporterInterface> mReporter;
};
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 44f3baf..7843923 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -136,9 +136,6 @@
/* Notifies the policy that the drag window has moved over to another window */
virtual void notifyDropWindow(const sp<IBinder>& token, float x, float y) = 0;
-
- /* If touch mode is enabled per display or global */
- virtual bool isPerDisplayTouchModeEnabled() = 0;
};
} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 7ee6950..985c9c5 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,10 +63,14 @@
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
-// The default pid and uid for windows created by the test.
+// The default pid and uid for windows created on the primary display by the test.
static constexpr int32_t WINDOW_PID = 999;
static constexpr int32_t WINDOW_UID = 1001;
+// The default pid and uid for the windows created on the secondary display by the test.
+static constexpr int32_t SECONDARY_WINDOW_PID = 1010;
+static constexpr int32_t SECONDARY_WINDOW_UID = 1012;
+
// The default policy flags to use for event injection by tests.
static constexpr uint32_t DEFAULT_POLICY_FLAGS = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
@@ -500,11 +504,6 @@
verify(*mFilteredEvent);
mFilteredEvent = nullptr;
}
-
- bool isPerDisplayTouchModeEnabled() {
- // TODO(b/198499018): Make this a regular property once per display touch mode is enabled
- return false;
- }
};
// --- InputDispatcherTest ---
@@ -5461,7 +5460,6 @@
sp<FakeWindowHandle>::make(mApplication, mDispatcher,
"Window without input channel", ADISPLAY_ID_DEFAULT,
std::make_optional<sp<IBinder>>(nullptr) /*token*/);
-
mNoInputWindow->setNoInputChannel(true);
mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
// It's perfectly valid for this window to not have an associated input channel
@@ -6806,44 +6804,67 @@
class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
protected:
std::shared_ptr<FakeApplicationHandle> mApp;
+ std::shared_ptr<FakeApplicationHandle> mSecondaryApp;
sp<FakeWindowHandle> mWindow;
sp<FakeWindowHandle> mSecondWindow;
+ sp<FakeWindowHandle> mThirdWindow;
void SetUp() override {
InputDispatcherTest::SetUp();
mApp = std::make_shared<FakeApplicationHandle>();
+ mSecondaryApp = std::make_shared<FakeApplicationHandle>();
mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFocusable(true);
setFocusedWindow(mWindow);
mSecondWindow =
sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFocusable(true);
+ mThirdWindow =
+ sp<FakeWindowHandle>::make(mSecondaryApp, mDispatcher,
+ "TestWindow3_SecondaryDisplay", SECOND_DISPLAY_ID);
+ mThirdWindow->setFocusable(true);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}},
+ {SECOND_DISPLAY_ID, {mThirdWindow}}});
+ mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID);
mWindow->consumeFocusEvent(true);
- // Set initial touch mode to InputDispatcher::kDefaultInTouchMode.
+ // Set main display initial touch mode to InputDispatcher::kDefaultInTouchMode.
if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID,
- WINDOW_UID, true /*hasPermission*/, ADISPLAY_ID_DEFAULT)) {
+ WINDOW_UID, true /* hasPermission */,
+ ADISPLAY_ID_DEFAULT)) {
mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
+ mThirdWindow->assertNoEvents();
+ }
+
+ // Set secondary display initial touch mode to InputDispatcher::kDefaultInTouchMode.
+ if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, SECONDARY_WINDOW_PID,
+ SECONDARY_WINDOW_UID, true /* hasPermission */,
+ SECOND_DISPLAY_ID)) {
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+ mThirdWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode);
}
}
- void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
+ void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, int32_t pid, int32_t uid,
+ bool hasPermission) {
ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
ADISPLAY_ID_DEFAULT));
mWindow->consumeTouchModeEvent(inTouchMode);
mSecondWindow->consumeTouchModeEvent(inTouchMode);
+ mThirdWindow->assertNoEvents();
}
};
TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) {
const WindowInfo& windowInfo = *mWindow->getInfo();
- changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
- windowInfo.ownerUid, false /*hasPermission*/);
+ changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode,
+ windowInfo.ownerPid, windowInfo.ownerUid,
+ false /* hasPermission */);
}
TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
@@ -6863,8 +6884,8 @@
int32_t ownerPid = windowInfo.ownerPid;
int32_t ownerUid = windowInfo.ownerUid;
mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
- changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid,
- true /*hasPermission*/);
+ changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
+ ownerUid, true /*hasPermission*/);
}
TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
@@ -6876,6 +6897,16 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) {
+ const WindowInfo& windowInfo = *mThirdWindow->getInfo();
+ ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode,
+ windowInfo.ownerPid, windowInfo.ownerUid,
+ true /*hasPermission*/, SECOND_DISPLAY_ID));
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+ mThirdWindow->consumeTouchModeEvent(!InputDispatcher::kDefaultInTouchMode);
+}
+
TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) {
// Interact with the window first.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))