Add setFocusedWindow function stub
This function, once implemented, will set focus on the specified
window. This is the first step in changing focus selection from
setInputWindows and using explicit call which will help us more
easily decouple z-order from focus selection and support focus
for SurfaceViewHost surfaces.
Bug: 151179149
Test: presubmit
Test: go/wm-smoke
Test: atest inputflinger_tests
Change-Id: Ib2254b4ab3ba8d579dfe49ddf3286f8ce2eecf9e
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 088c6f1..e49667e 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -146,4 +146,9 @@
return NO_ERROR;
}
+binder::Status InputManager::setFocusedWindow(const FocusRequest& request) {
+ mDispatcher->setFocusedWindow(request);
+ return binder::Status::ok();
+}
+
} // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 0503e81..bf86a98 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -110,6 +110,7 @@
binder::Status registerInputChannel(const InputChannel& channel) override;
binder::Status unregisterInputChannel(const InputChannel& channel) override;
+ binder::Status setFocusedWindow(const FocusRequest&) override;
private:
sp<InputReaderInterface> mReader;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index da09898..0493130 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -5186,4 +5186,19 @@
return result == std::cv_status::no_timeout;
}
+/**
+ * Sets focus to the window identified by the token. This must be called
+ * after updating any input window handles.
+ *
+ * Params:
+ * request.token - input channel token used to identify the window that should gain focus.
+ * request.focusedToken - the token that the caller expects currently to be focused. If the
+ * specified token does not match the currently focused window, this request will be dropped.
+ * If the specified focused token matches the currently focused window, the call will succeed.
+ * Set this to "null" if this call should succeed no matter what the currently focused token is.
+ * request.timestamp - SYSTEM_TIME_MONOTONIC timestamp in nanos set by the client (wm)
+ * when requesting the focus change. This determines which request gets
+ * precedence if there is a focus change request from another source such as pointer down.
+ */
+void InputDispatcher::setFocusedWindow(const FocusRequest&) {}
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index ba7ace0..b4d1079 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -126,6 +126,7 @@
virtual status_t registerInputChannel(
const std::shared_ptr<InputChannel>& inputChannel) override;
+ virtual void setFocusedWindow(const FocusRequest&) override;
virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
int32_t displayId, bool isGestureMonitor) override;
virtual status_t unregisterInputChannel(const InputChannel& inputChannel) override;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 272b0a6..f97c880 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -18,6 +18,7 @@
#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
#include <InputListener.h>
+#include <android/FocusRequest.h>
#include <android/os/ISetInputWindowsListener.h>
#include <input/InputApplication.h>
#include <input/InputTransport.h>
@@ -148,6 +149,11 @@
*/
virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
+ /**
+ * Sets focus on the specified window.
+ */
+ virtual void setFocusedWindow(const FocusRequest&) = 0;
+
/* Registers input channels that may be used as targets for input events.
*
* This method may be called on any thread (usually by the input manager).
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index cd655e0..2a2cea5 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -50,6 +50,7 @@
}
binder::Status registerInputChannel(const InputChannel&) { return binder::Status::ok(); }
binder::Status unregisterInputChannel(const InputChannel&) { return binder::Status::ok(); }
+ binder::Status setFocusedWindow(const FocusRequest&) { return binder::Status::ok(); }
private:
virtual ~InputFlinger();
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index eb9ac68..6465cc9 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -30,14 +30,14 @@
"AnrTracker_test.cpp",
"BlockingQueue_test.cpp",
"EventHub_test.cpp",
- "TestInputListener.cpp",
+ "IInputFlingerQuery.aidl",
"InputClassifier_test.cpp",
"InputClassifierConverter_test.cpp",
"InputDispatcher_test.cpp",
"InputReader_test.cpp",
"InputFlingerService_test.cpp",
+ "TestInputListener.cpp",
"UinputDevice.cpp",
- "IInputFlingerQuery.aidl"
],
aidl: {
include_dirs: [
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index 755373b..b5c5c9e 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import android.FocusRequest;
import android.InputChannel;
import android.InputWindowInfo;
import android.os.ISetInputWindowsListener;
@@ -24,4 +25,5 @@
/* Test interfaces */
void getInputWindows(out InputWindowInfo[] inputHandles);
void getInputChannels(out InputChannel[] channels);
+ void getLastFocusRequest(out FocusRequest request);
}
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index b88bc52..282b4fa 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -55,6 +55,7 @@
namespace android {
static const sp<IBinder> TestInfoToken = new BBinder();
+static const sp<IBinder> FocusedTestInfoToken = new BBinder();
static constexpr int32_t TestInfoId = 1;
static const std::string TestInfoName = "InputFlingerServiceTestInputWindowInfo";
static constexpr Flags<InputWindowInfo::Flag> TestInfoFlags = InputWindowInfo::Flag::NOT_FOCUSABLE;
@@ -102,7 +103,9 @@
protected:
void InitializeInputFlinger();
- void setInputWindowsByInfos(std::vector<InputWindowInfo>& infos);
+ void setInputWindowsByInfos(const std::vector<InputWindowInfo>& infos);
+ void setFocusedWindow(const sp<IBinder> token, const sp<IBinder> focusedToken,
+ nsecs_t timestampNanos);
void setInputWindowsFinished();
void verifyInputWindowInfo(const InputWindowInfo& info) const;
@@ -137,6 +140,7 @@
binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
+ binder::Status getLastFocusRequest(FocusRequest*);
status_t dump(int fd, const Vector<String16>& args) override;
@@ -146,11 +150,13 @@
binder::Status registerInputChannel(const InputChannel& channel) override;
binder::Status unregisterInputChannel(const InputChannel& channel) override;
+ binder::Status setFocusedWindow(const FocusRequest&) override;
private:
mutable Mutex mLock;
std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
std::vector<std::shared_ptr<InputChannel>> mInputChannels;
+ FocusRequest mFocusRequest;
};
class TestInputQuery : public BnInputFlingerQuery {
@@ -158,6 +164,7 @@
TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
+ binder::Status getLastFocusRequest(FocusRequest*) override;
private:
sp<android::TestInputManager> mManager;
@@ -172,6 +179,10 @@
return mManager->getInputChannels(channels);
}
+binder::Status TestInputQuery::getLastFocusRequest(FocusRequest* request) {
+ return mManager->getLastFocusRequest(request);
+}
+
binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
if (mCbFunc != nullptr) {
mCbFunc();
@@ -251,6 +262,16 @@
return binder::Status::ok();
}
+binder::Status TestInputManager::getLastFocusRequest(FocusRequest* request) {
+ *request = mFocusRequest;
+ return binder::Status::ok();
+}
+
+binder::Status TestInputManager::setFocusedWindow(const FocusRequest& request) {
+ mFocusRequest = request;
+ return binder::Status::ok();
+}
+
void InputFlingerServiceTest::SetUp() {
mSetInputWindowsListener = new SetInputWindowsListener([&]() {
std::unique_lock<std::mutex> lock(mLock);
@@ -310,13 +331,25 @@
mQuery = interface_cast<IInputFlingerQuery>(input);
}
-void InputFlingerServiceTest::setInputWindowsByInfos(std::vector<InputWindowInfo>& infos) {
+void InputFlingerServiceTest::setInputWindowsByInfos(const std::vector<InputWindowInfo>& infos) {
std::unique_lock<std::mutex> lock(mLock);
mService->setInputWindows(infos, mSetInputWindowsListener);
// Verify listener call
EXPECT_NE(mSetInputWindowsFinishedCondition.wait_for(lock, 1s), std::cv_status::timeout);
}
+void InputFlingerServiceTest::setFocusedWindow(const sp<IBinder> token,
+ const sp<IBinder> focusedToken,
+ nsecs_t timestampNanos) {
+ FocusRequest request;
+ request.token = TestInfoToken;
+ request.focusedToken = focusedToken;
+ request.timestamp = timestampNanos;
+ mService->setFocusedWindow(request);
+ // call set input windows and wait for the callback to drain the queue.
+ setInputWindowsByInfos(std::vector<InputWindowInfo>());
+}
+
/**
* Test InputFlinger service interface SetInputWindows
*/
@@ -376,6 +409,30 @@
EXPECT_EQ(channels.size(), 0UL);
}
+TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindow) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ setFocusedWindow(TestInfoToken, nullptr /* focusedToken */, now);
+
+ FocusRequest request;
+ mQuery->getLastFocusRequest(&request);
+
+ EXPECT_EQ(request.token, TestInfoToken);
+ EXPECT_EQ(request.focusedToken, nullptr);
+ EXPECT_EQ(request.timestamp, now);
+}
+
+TEST_F(InputFlingerServiceTest, InputWindow_setFocusedWindowWithFocusedToken) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ setFocusedWindow(TestInfoToken, FocusedTestInfoToken, now);
+
+ FocusRequest request;
+ mQuery->getLastFocusRequest(&request);
+
+ EXPECT_EQ(request.token, TestInfoToken);
+ EXPECT_EQ(request.focusedToken, FocusedTestInfoToken);
+ EXPECT_EQ(request.timestamp, now);
+}
+
} // namespace android
int main(int argc, char** argv) {