Divide InputDispatcher into several files.
This CL does:
1) Isolate implementation details of InputDispatcher from outside and
only expose necessary header files;
2) Move implementation details into android::inputdispatcher namespace;
3) Make input dispatcher a static library for inputflinger to link
against;
4) Add InputDispatcherFactory.{h,cpp} to isolate implementation details
in InputDispatcher.h from InputManager.
Bug: 140139676
Test: Touches on touchscreen can be dispatched to right windows.
Change-Id: Ib61c16fd41f3f76f538a3de9b54f31ac304e03a5
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 8649c1e..32dab174 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -30,7 +30,6 @@
srcs: [
"InputClassifier.cpp",
"InputClassifierConverter.cpp",
- "dispatcher/InputDispatcher.cpp",
"InputManager.cpp",
],
@@ -50,6 +49,10 @@
"server_configurable_flags",
],
+ static_libs: [
+ "libinputdispatcher",
+ ],
+
cflags: [
// TODO(b/23084678): Move inputflinger to its own process and mark it hidden
//-fvisibility=hidden
@@ -58,14 +61,18 @@
export_include_dirs: [
".",
"include",
- "dispatcher",
],
+ export_static_lib_headers: [
+ "libinputdispatcher",
+ ],
}
cc_library_headers {
name: "libinputflinger_headers",
+ header_libs: ["libinputreporter_headers"],
export_include_dirs: ["include"],
+ export_header_lib_headers: ["libinputreporter_headers"],
}
cc_library_shared {
@@ -125,28 +132,6 @@
],
}
-cc_library_shared {
- name: "libinputreporter",
- defaults: ["inputflinger_defaults"],
-
- srcs: [
- "InputReporter.cpp",
- ],
-
- shared_libs: [
- "liblog",
- "libutils",
- ],
-
- header_libs: [
- "libinputflinger_headers",
- ],
-
- export_header_lib_headers: [
- "libinputflinger_headers",
- ],
-}
-
subdirs = [
"host",
"tests",
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 3996cca..359325f 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -19,6 +19,8 @@
//#define LOG_NDEBUG 0
#include "InputManager.h"
+#include "InputDispatcherFactory.h"
+#include "InputDispatcherThread.h"
#include "InputReaderFactory.h"
#include <binder/IPCThreadState.h>
@@ -33,7 +35,7 @@
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
- mDispatcher = new InputDispatcher(dispatcherPolicy);
+ mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
initialize();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index e568df5..ba0b287 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -22,14 +22,15 @@
*/
#include "EventHub.h"
-#include "InputReaderBase.h"
#include "InputClassifier.h"
-#include "InputDispatcher.h"
#include "InputReader.h"
+#include "InputReaderBase.h"
+#include <InputDispatcherInterface.h>
+#include <InputDispatcherPolicyInterface.h>
+#include <input/ISetInputWindowsListener.h>
#include <input/Input.h>
#include <input/InputTransport.h>
-#include <input/ISetInputWindowsListener.h>
#include <input/IInputFlinger.h>
#include <utils/Errors.h>
@@ -39,6 +40,7 @@
namespace android {
class InputChannel;
+class InputDispatcherThread;
/*
* The input manager is the core of the system event processing.
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
new file mode 100644
index 0000000..b8c3a80
--- /dev/null
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+ name: "libinputdispatcher",
+ defaults: ["inputflinger_defaults"],
+ srcs: [
+ "Connection.cpp",
+ "Entry.cpp",
+ "InjectionState.cpp",
+ "InputDispatcher.cpp",
+ "InputDispatcherFactory.cpp",
+ "InputDispatcherThread.cpp",
+ "InputState.cpp",
+ "InputTarget.cpp",
+ "Monitor.cpp",
+ "TouchState.cpp"
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libinput",
+ "libinputreporter",
+ "libinputflinger_base",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+
+ export_include_dirs: ["include"],
+}
diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h
new file mode 100644
index 0000000..99e2108
--- /dev/null
+++ b/services/inputflinger/dispatcher/CancelationOptions.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
+#define _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
+
+#include <optional>
+
+namespace android::inputdispatcher {
+
+/* Specifies which events are to be canceled and why. */
+struct CancelationOptions {
+ enum Mode {
+ CANCEL_ALL_EVENTS = 0,
+ CANCEL_POINTER_EVENTS = 1,
+ CANCEL_NON_POINTER_EVENTS = 2,
+ CANCEL_FALLBACK_EVENTS = 3,
+ };
+
+ // The criterion to use to determine which events should be canceled.
+ Mode mode;
+
+ // Descriptive reason for the cancelation.
+ const char* reason;
+
+ // The specific keycode of the key event to cancel, or nullopt to cancel any key event.
+ std::optional<int32_t> keyCode = std::nullopt;
+
+ // The specific device id of events to cancel, or nullopt to cancel events from any device.
+ std::optional<int32_t> deviceId = std::nullopt;
+
+ // The specific display id of events to cancel, or nullopt to cancel events on any display.
+ std::optional<int32_t> displayId = std::nullopt;
+
+ CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) {}
+};
+
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp
new file mode 100644
index 0000000..6f82f4f
--- /dev/null
+++ b/services/inputflinger/dispatcher/Connection.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Connection.h"
+
+#include "Entry.h"
+
+namespace android::inputdispatcher {
+
+Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor)
+ : status(STATUS_NORMAL),
+ inputChannel(inputChannel),
+ monitor(monitor),
+ inputPublisher(inputChannel),
+ inputPublisherBlocked(false) {}
+
+Connection::~Connection() {}
+
+const std::string Connection::getWindowName() const {
+ if (inputChannel != nullptr) {
+ return inputChannel->getName();
+ }
+ if (monitor) {
+ return "monitor";
+ }
+ return "?";
+}
+
+const char* Connection::getStatusLabel() const {
+ switch (status) {
+ case STATUS_NORMAL:
+ return "NORMAL";
+ case STATUS_BROKEN:
+ return "BROKEN";
+ case STATUS_ZOMBIE:
+ return "ZOMBIE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+std::deque<DispatchEntry*>::iterator Connection::findWaitQueueEntry(uint32_t seq) {
+ for (std::deque<DispatchEntry*>::iterator it = waitQueue.begin(); it != waitQueue.end(); it++) {
+ if ((*it)->seq == seq) {
+ return it;
+ }
+ }
+ return waitQueue.end();
+}
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h
new file mode 100644
index 0000000..8423010
--- /dev/null
+++ b/services/inputflinger/dispatcher/Connection.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_CONNECTION_H
+#define _UI_INPUT_INPUTDISPATCHER_CONNECTION_H
+
+#include "InputState.h"
+
+#include <input/InputTransport.h>
+#include <deque>
+
+namespace android::inputdispatcher {
+
+struct DispatchEntry;
+
+/* Manages the dispatch state associated with a single input channel. */
+class Connection : public RefBase {
+protected:
+ virtual ~Connection();
+
+public:
+ enum Status {
+ // Everything is peachy.
+ STATUS_NORMAL,
+ // An unrecoverable communication error has occurred.
+ STATUS_BROKEN,
+ // The input channel has been unregistered.
+ STATUS_ZOMBIE
+ };
+
+ Status status;
+ sp<InputChannel> inputChannel; // never null
+ bool monitor;
+ InputPublisher inputPublisher;
+ InputState inputState;
+
+ // True if the socket is full and no further events can be published until
+ // the application consumes some of the input.
+ bool inputPublisherBlocked;
+
+ // Queue of events that need to be published to the connection.
+ std::deque<DispatchEntry*> outboundQueue;
+
+ // Queue of events that have been published to the connection but that have not
+ // yet received a "finished" response from the application.
+ std::deque<DispatchEntry*> waitQueue;
+
+ explicit Connection(const sp<InputChannel>& inputChannel, bool monitor);
+
+ inline const std::string getInputChannelName() const { return inputChannel->getName(); }
+
+ const std::string getWindowName() const;
+ const char* getStatusLabel() const;
+
+ std::deque<DispatchEntry*>::iterator findWaitQueueEntry(uint32_t seq);
+};
+
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_INPUTDISPATCHER_CONNECTION_H
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
new file mode 100644
index 0000000..640a69a
--- /dev/null
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Entry.h"
+
+#include "Connection.h"
+
+#include <android-base/stringprintf.h>
+#include <cutils/atomic.h>
+#include <inttypes.h>
+
+using android::base::StringPrintf;
+
+namespace android::inputdispatcher {
+
+static std::string motionActionToString(int32_t action) {
+ // Convert MotionEvent action to string
+ switch (action & AMOTION_EVENT_ACTION_MASK) {
+ case AMOTION_EVENT_ACTION_DOWN:
+ return "DOWN";
+ case AMOTION_EVENT_ACTION_MOVE:
+ return "MOVE";
+ case AMOTION_EVENT_ACTION_UP:
+ return "UP";
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
+ return "POINTER_DOWN";
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ return "POINTER_UP";
+ }
+ return StringPrintf("%" PRId32, action);
+}
+
+static std::string keyActionToString(int32_t action) {
+ // Convert KeyEvent action to string
+ switch (action) {
+ case AKEY_EVENT_ACTION_DOWN:
+ return "DOWN";
+ case AKEY_EVENT_ACTION_UP:
+ return "UP";
+ case AKEY_EVENT_ACTION_MULTIPLE:
+ return "MULTIPLE";
+ }
+ return StringPrintf("%" PRId32, action);
+}
+
+// --- EventEntry ---
+
+EventEntry::EventEntry(uint32_t sequenceNum, int32_t type, nsecs_t eventTime, uint32_t policyFlags)
+ : sequenceNum(sequenceNum),
+ refCount(1),
+ type(type),
+ eventTime(eventTime),
+ policyFlags(policyFlags),
+ injectionState(nullptr),
+ dispatchInProgress(false) {}
+
+EventEntry::~EventEntry() {
+ releaseInjectionState();
+}
+
+void EventEntry::release() {
+ refCount -= 1;
+ if (refCount == 0) {
+ delete this;
+ } else {
+ ALOG_ASSERT(refCount > 0);
+ }
+}
+
+void EventEntry::releaseInjectionState() {
+ if (injectionState) {
+ injectionState->release();
+ injectionState = nullptr;
+ }
+}
+
+// --- ConfigurationChangedEntry ---
+
+ConfigurationChangedEntry::ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime)
+ : EventEntry(sequenceNum, TYPE_CONFIGURATION_CHANGED, eventTime, 0) {}
+
+ConfigurationChangedEntry::~ConfigurationChangedEntry() {}
+
+void ConfigurationChangedEntry::appendDescription(std::string& msg) const {
+ msg += StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags);
+}
+
+// --- DeviceResetEntry ---
+
+DeviceResetEntry::DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId)
+ : EventEntry(sequenceNum, TYPE_DEVICE_RESET, eventTime, 0), deviceId(deviceId) {}
+
+DeviceResetEntry::~DeviceResetEntry() {}
+
+void DeviceResetEntry::appendDescription(std::string& msg) const {
+ msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags);
+}
+
+// --- KeyEntry ---
+
+KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+ int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags,
+ int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount,
+ nsecs_t downTime)
+ : EventEntry(sequenceNum, TYPE_KEY, eventTime, policyFlags),
+ deviceId(deviceId),
+ source(source),
+ displayId(displayId),
+ action(action),
+ flags(flags),
+ keyCode(keyCode),
+ scanCode(scanCode),
+ metaState(metaState),
+ repeatCount(repeatCount),
+ downTime(downTime),
+ syntheticRepeat(false),
+ interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN),
+ interceptKeyWakeupTime(0) {}
+
+KeyEntry::~KeyEntry() {}
+
+void KeyEntry::appendDescription(std::string& msg) const {
+ msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, "
+ "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
+ "repeatCount=%d), policyFlags=0x%08x",
+ deviceId, source, displayId, keyActionToString(action).c_str(), flags,
+ keyCode, scanCode, metaState, repeatCount, policyFlags);
+}
+
+void KeyEntry::recycle() {
+ releaseInjectionState();
+
+ dispatchInProgress = false;
+ syntheticRepeat = false;
+ interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
+ interceptKeyWakeupTime = 0;
+}
+
+// --- MotionEntry ---
+
+MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+ int32_t displayId, uint32_t policyFlags, int32_t action,
+ int32_t actionButton, int32_t flags, int32_t metaState,
+ int32_t buttonState, MotionClassification classification,
+ int32_t edgeFlags, float xPrecision, float yPrecision,
+ float xCursorPosition, float yCursorPosition, nsecs_t downTime,
+ uint32_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords, float xOffset, float yOffset)
+ : EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags),
+ eventTime(eventTime),
+ deviceId(deviceId),
+ source(source),
+ displayId(displayId),
+ action(action),
+ actionButton(actionButton),
+ flags(flags),
+ metaState(metaState),
+ buttonState(buttonState),
+ classification(classification),
+ edgeFlags(edgeFlags),
+ xPrecision(xPrecision),
+ yPrecision(yPrecision),
+ xCursorPosition(xCursorPosition),
+ yCursorPosition(yCursorPosition),
+ downTime(downTime),
+ pointerCount(pointerCount) {
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ this->pointerProperties[i].copyFrom(pointerProperties[i]);
+ this->pointerCoords[i].copyFrom(pointerCoords[i]);
+ if (xOffset || yOffset) {
+ this->pointerCoords[i].applyOffset(xOffset, yOffset);
+ }
+ }
+}
+
+MotionEntry::~MotionEntry() {}
+
+void MotionEntry::appendDescription(std::string& msg) const {
+ msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
+ ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, "
+ "buttonState=0x%08x, "
+ "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, "
+ "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[",
+ deviceId, source, displayId, motionActionToString(action).c_str(),
+ actionButton, flags, metaState, buttonState,
+ motionClassificationToString(classification), edgeFlags, xPrecision,
+ yPrecision, xCursorPosition, yCursorPosition);
+
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ if (i) {
+ msg += ", ";
+ }
+ msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id, pointerCoords[i].getX(),
+ pointerCoords[i].getY());
+ }
+ msg += StringPrintf("]), policyFlags=0x%08x", policyFlags);
+}
+
+// --- DispatchEntry ---
+
+volatile int32_t DispatchEntry::sNextSeqAtomic;
+
+DispatchEntry::DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset,
+ float yOffset, float globalScaleFactor, float windowXScale,
+ float windowYScale)
+ : seq(nextSeq()),
+ eventEntry(eventEntry),
+ targetFlags(targetFlags),
+ xOffset(xOffset),
+ yOffset(yOffset),
+ globalScaleFactor(globalScaleFactor),
+ windowXScale(windowXScale),
+ windowYScale(windowYScale),
+ deliveryTime(0),
+ resolvedAction(0),
+ resolvedFlags(0) {
+ eventEntry->refCount += 1;
+}
+
+DispatchEntry::~DispatchEntry() {
+ eventEntry->release();
+}
+
+uint32_t DispatchEntry::nextSeq() {
+ // Sequence number 0 is reserved and will never be returned.
+ uint32_t seq;
+ do {
+ seq = android_atomic_inc(&sNextSeqAtomic);
+ } while (!seq);
+ return seq;
+}
+
+// --- CommandEntry ---
+
+CommandEntry::CommandEntry(Command command)
+ : command(command),
+ eventTime(0),
+ keyEntry(nullptr),
+ userActivityEventType(0),
+ seq(0),
+ handled(false) {}
+
+CommandEntry::~CommandEntry() {}
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
new file mode 100644
index 0000000..a9e22f1
--- /dev/null
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_ENTRY_H
+#define _UI_INPUT_INPUTDISPATCHER_ENTRY_H
+
+#include "InjectionState.h"
+#include "InputTarget.h"
+
+#include <input/Input.h>
+#include <input/InputApplication.h>
+#include <stdint.h>
+#include <utils/Timers.h>
+#include <functional>
+#include <string>
+
+namespace android::inputdispatcher {
+
+struct EventEntry {
+ enum { TYPE_CONFIGURATION_CHANGED, TYPE_DEVICE_RESET, TYPE_KEY, TYPE_MOTION };
+
+ uint32_t sequenceNum;
+ mutable int32_t refCount;
+ int32_t type;
+ nsecs_t eventTime;
+ uint32_t policyFlags;
+ InjectionState* injectionState;
+
+ bool dispatchInProgress; // initially false, set to true while dispatching
+
+ inline bool isInjected() const { return injectionState != nullptr; }
+
+ void release();
+
+ virtual void appendDescription(std::string& msg) const = 0;
+
+protected:
+ EventEntry(uint32_t sequenceNum, int32_t type, nsecs_t eventTime, uint32_t policyFlags);
+ virtual ~EventEntry();
+ void releaseInjectionState();
+};
+
+struct ConfigurationChangedEntry : EventEntry {
+ explicit ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime);
+ virtual void appendDescription(std::string& msg) const;
+
+protected:
+ virtual ~ConfigurationChangedEntry();
+};
+
+struct DeviceResetEntry : EventEntry {
+ int32_t deviceId;
+
+ DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId);
+ virtual void appendDescription(std::string& msg) const;
+
+protected:
+ virtual ~DeviceResetEntry();
+};
+
+struct KeyEntry : EventEntry {
+ int32_t deviceId;
+ uint32_t source;
+ int32_t displayId;
+ int32_t action;
+ int32_t flags;
+ int32_t keyCode;
+ int32_t scanCode;
+ int32_t metaState;
+ int32_t repeatCount;
+ nsecs_t downTime;
+
+ bool syntheticRepeat; // set to true for synthetic key repeats
+
+ enum InterceptKeyResult {
+ INTERCEPT_KEY_RESULT_UNKNOWN,
+ INTERCEPT_KEY_RESULT_SKIP,
+ INTERCEPT_KEY_RESULT_CONTINUE,
+ INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER,
+ };
+ InterceptKeyResult interceptKeyResult; // set based on the interception result
+ nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER
+
+ KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+ int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags,
+ int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount,
+ nsecs_t downTime);
+ virtual void appendDescription(std::string& msg) const;
+ void recycle();
+
+protected:
+ virtual ~KeyEntry();
+};
+
+struct MotionEntry : EventEntry {
+ nsecs_t eventTime;
+ int32_t deviceId;
+ uint32_t source;
+ int32_t displayId;
+ int32_t action;
+ int32_t actionButton;
+ int32_t flags;
+ int32_t metaState;
+ int32_t buttonState;
+ MotionClassification classification;
+ int32_t edgeFlags;
+ float xPrecision;
+ float yPrecision;
+ float xCursorPosition;
+ float yCursorPosition;
+ nsecs_t downTime;
+ uint32_t pointerCount;
+ PointerProperties pointerProperties[MAX_POINTERS];
+ PointerCoords pointerCoords[MAX_POINTERS];
+
+ MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+ int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
+ int32_t flags, int32_t metaState, int32_t buttonState,
+ MotionClassification classification, int32_t edgeFlags, float xPrecision,
+ float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime,
+ uint32_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords, float xOffset, float yOffset);
+ virtual void appendDescription(std::string& msg) const;
+
+protected:
+ virtual ~MotionEntry();
+};
+
+// Tracks the progress of dispatching a particular event to a particular connection.
+struct DispatchEntry {
+ const uint32_t seq; // unique sequence number, never 0
+
+ EventEntry* eventEntry; // the event to dispatch
+ int32_t targetFlags;
+ float xOffset;
+ float yOffset;
+ float globalScaleFactor;
+ float windowXScale = 1.0f;
+ float windowYScale = 1.0f;
+ nsecs_t deliveryTime; // time when the event was actually delivered
+
+ // Set to the resolved action and flags when the event is enqueued.
+ int32_t resolvedAction;
+ int32_t resolvedFlags;
+
+ DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, float yOffset,
+ float globalScaleFactor, float windowXScale, float windowYScale);
+ ~DispatchEntry();
+
+ inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
+
+ inline bool isSplit() const { return targetFlags & InputTarget::FLAG_SPLIT; }
+
+private:
+ static volatile int32_t sNextSeqAtomic;
+
+ static uint32_t nextSeq();
+};
+
+class InputDispatcher;
+// A command entry captures state and behavior for an action to be performed in the
+// dispatch loop after the initial processing has taken place. It is essentially
+// a kind of continuation used to postpone sensitive policy interactions to a point
+// in the dispatch loop where it is safe to release the lock (generally after finishing
+// the critical parts of the dispatch cycle).
+//
+// The special thing about commands is that they can voluntarily release and reacquire
+// the dispatcher lock at will. Initially when the command starts running, the
+// dispatcher lock is held. However, if the command needs to call into the policy to
+// do some work, it can release the lock, do the work, then reacquire the lock again
+// before returning.
+//
+// This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
+// never calls into the policy while holding its lock.
+//
+// Commands are implicitly 'LockedInterruptible'.
+struct CommandEntry;
+typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
+
+class Connection;
+struct CommandEntry {
+ explicit CommandEntry(Command command);
+ ~CommandEntry();
+
+ Command command;
+
+ // parameters for the command (usage varies by command)
+ sp<Connection> connection;
+ nsecs_t eventTime;
+ KeyEntry* keyEntry;
+ sp<InputApplicationHandle> inputApplicationHandle;
+ std::string reason;
+ int32_t userActivityEventType;
+ uint32_t seq;
+ bool handled;
+ sp<InputChannel> inputChannel;
+ sp<IBinder> oldToken;
+ sp<IBinder> newToken;
+};
+
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_INPUTDISPATCHER_ENTRY_H
diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp
new file mode 100644
index 0000000..b2d0a26
--- /dev/null
+++ b/services/inputflinger/dispatcher/InjectionState.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InjectionState.h"
+
+#include <log/log.h>
+
+namespace android::inputdispatcher {
+
+InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid)
+ : refCount(1),
+ injectorPid(injectorPid),
+ injectorUid(injectorUid),
+ injectionResult(INPUT_EVENT_INJECTION_PENDING),
+ injectionIsAsync(false),
+ pendingForegroundDispatches(0) {}
+
+InjectionState::~InjectionState() {}
+
+void InjectionState::release() {
+ refCount -= 1;
+ if (refCount == 0) {
+ delete this;
+ } else {
+ ALOG_ASSERT(refCount > 0);
+ }
+}
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
new file mode 100644
index 0000000..311a0f1
--- /dev/null
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H
+#define _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H
+
+#include "InputDispatcherInterface.h"
+
+#include <stdint.h>
+
+namespace android::inputdispatcher {
+
+/*
+ * Constants used to determine the input event injection synchronization mode.
+ */
+enum {
+ /* Injection is asynchronous and is assumed always to be successful. */
+ INPUT_EVENT_INJECTION_SYNC_NONE = 0,
+
+ /* Waits for previous events to be dispatched so that the input dispatcher can determine
+ * whether input event injection willbe permitted based on the current input focus.
+ * Does not wait for the input event to finish processing. */
+ INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1,
+
+ /* Waits for the input event to be completely processed. */
+ INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2,
+};
+
+struct InjectionState {
+ mutable int32_t refCount;
+
+ int32_t injectorPid;
+ int32_t injectorUid;
+ int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING
+ bool injectionIsAsync; // set to true if injection is not waiting for the result
+ int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
+
+ InjectionState(int32_t injectorPid, int32_t injectorUid);
+ void release();
+
+private:
+ ~InjectionState();
+};
+
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4b8c51b..039462e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -45,6 +45,8 @@
#include "InputDispatcher.h"
+#include "Connection.h"
+
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
@@ -68,7 +70,7 @@
using android::base::StringPrintf;
-namespace android {
+namespace android::inputdispatcher {
// Default input dispatching timeout if there is no focused application or paused window
// from which to determine an appropriate dispatching timeout.
@@ -98,9 +100,6 @@
// Number of recent events to keep for debugging purposes.
constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;
-// Sequence number for synthesized or injected events.
-constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0;
-
static inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
}
@@ -109,54 +108,6 @@
return value ? "true" : "false";
}
-static std::string motionActionToString(int32_t action) {
- // Convert MotionEvent action to string
- switch (action & AMOTION_EVENT_ACTION_MASK) {
- case AMOTION_EVENT_ACTION_DOWN:
- return "DOWN";
- case AMOTION_EVENT_ACTION_MOVE:
- return "MOVE";
- case AMOTION_EVENT_ACTION_UP:
- return "UP";
- case AMOTION_EVENT_ACTION_POINTER_DOWN:
- return "POINTER_DOWN";
- case AMOTION_EVENT_ACTION_POINTER_UP:
- return "POINTER_UP";
- }
- return StringPrintf("%" PRId32, action);
-}
-
-static std::string keyActionToString(int32_t action) {
- // Convert KeyEvent action to string
- switch (action) {
- case AKEY_EVENT_ACTION_DOWN:
- return "DOWN";
- case AKEY_EVENT_ACTION_UP:
- return "UP";
- case AKEY_EVENT_ACTION_MULTIPLE:
- return "MULTIPLE";
- }
- return StringPrintf("%" PRId32, action);
-}
-
-static std::string dispatchModeToString(int32_t dispatchMode) {
- switch (dispatchMode) {
- case InputTarget::FLAG_DISPATCH_AS_IS:
- return "DISPATCH_AS_IS";
- case InputTarget::FLAG_DISPATCH_AS_OUTSIDE:
- return "DISPATCH_AS_OUTSIDE";
- case InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER:
- return "DISPATCH_AS_HOVER_ENTER";
- case InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT:
- return "DISPATCH_AS_HOVER_EXIT";
- case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT:
- return "DISPATCH_AS_SLIPPERY_EXIT";
- case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER:
- return "DISPATCH_AS_SLIPPERY_ENTER";
- }
- return StringPrintf("%" PRId32, dispatchMode);
-}
-
static inline int32_t getMotionEventActionPointerIndex(int32_t action) {
return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
@@ -612,7 +563,7 @@
return nullptr;
}
-std::vector<InputDispatcher::TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked(
+std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked(
int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) {
std::vector<TouchedMonitor> touchedMonitors;
@@ -787,7 +738,7 @@
}
}
-InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
+KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
// Reuse the repeated key entry if it is otherwise unreferenced.
@@ -2589,8 +2540,8 @@
}
}
-InputDispatcher::MotionEntry* InputDispatcher::splitMotionEvent(
- const MotionEntry* originalMotionEntry, BitSet32 pointerIds) {
+MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry,
+ BitSet32 pointerIds) {
ALOG_ASSERT(pointerIds.value != 0);
uint32_t splitPointerIndexMap[MAX_POINTERS];
@@ -4101,8 +4052,7 @@
return std::nullopt;
}
-sp<InputDispatcher::Connection> InputDispatcher::getConnectionLocked(
- const sp<InputChannel>& inputChannel) {
+sp<Connection> InputDispatcher::getConnectionLocked(const sp<InputChannel>& inputChannel) {
if (inputChannel == nullptr) {
return nullptr;
}
@@ -4275,8 +4225,7 @@
const bool handled = commandEntry->handled;
// Handle post-event policy actions.
- std::deque<InputDispatcher::DispatchEntry*>::iterator dispatchEntryIt =
- connection->findWaitQueueEntry(seq);
+ std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
if (dispatchEntryIt == connection->waitQueue.end()) {
return;
}
@@ -4570,790 +4519,4 @@
mDispatcherIsAlive.wait(_l);
}
-// --- InputDispatcher::InjectionState ---
-
-InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid)
- : refCount(1),
- injectorPid(injectorPid),
- injectorUid(injectorUid),
- injectionResult(INPUT_EVENT_INJECTION_PENDING),
- injectionIsAsync(false),
- pendingForegroundDispatches(0) {}
-
-InputDispatcher::InjectionState::~InjectionState() {}
-
-void InputDispatcher::InjectionState::release() {
- refCount -= 1;
- if (refCount == 0) {
- delete this;
- } else {
- ALOG_ASSERT(refCount > 0);
- }
-}
-
-// --- InputDispatcher::EventEntry ---
-
-InputDispatcher::EventEntry::EventEntry(uint32_t sequenceNum, int32_t type, nsecs_t eventTime,
- uint32_t policyFlags)
- : sequenceNum(sequenceNum),
- refCount(1),
- type(type),
- eventTime(eventTime),
- policyFlags(policyFlags),
- injectionState(nullptr),
- dispatchInProgress(false) {}
-
-InputDispatcher::EventEntry::~EventEntry() {
- releaseInjectionState();
-}
-
-void InputDispatcher::EventEntry::release() {
- refCount -= 1;
- if (refCount == 0) {
- delete this;
- } else {
- ALOG_ASSERT(refCount > 0);
- }
-}
-
-void InputDispatcher::EventEntry::releaseInjectionState() {
- if (injectionState) {
- injectionState->release();
- injectionState = nullptr;
- }
-}
-
-// --- InputDispatcher::ConfigurationChangedEntry ---
-
-InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(uint32_t sequenceNum,
- nsecs_t eventTime)
- : EventEntry(sequenceNum, TYPE_CONFIGURATION_CHANGED, eventTime, 0) {}
-
-InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() {}
-
-void InputDispatcher::ConfigurationChangedEntry::appendDescription(std::string& msg) const {
- msg += StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags);
-}
-
-// --- InputDispatcher::DeviceResetEntry ---
-
-InputDispatcher::DeviceResetEntry::DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime,
- int32_t deviceId)
- : EventEntry(sequenceNum, TYPE_DEVICE_RESET, eventTime, 0), deviceId(deviceId) {}
-
-InputDispatcher::DeviceResetEntry::~DeviceResetEntry() {}
-
-void InputDispatcher::DeviceResetEntry::appendDescription(std::string& msg) const {
- msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x", deviceId, policyFlags);
-}
-
-// --- InputDispatcher::KeyEntry ---
-
-InputDispatcher::KeyEntry::KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
- uint32_t source, int32_t displayId, uint32_t policyFlags,
- int32_t action, int32_t flags, int32_t keyCode,
- int32_t scanCode, int32_t metaState, int32_t repeatCount,
- nsecs_t downTime)
- : EventEntry(sequenceNum, TYPE_KEY, eventTime, policyFlags),
- deviceId(deviceId),
- source(source),
- displayId(displayId),
- action(action),
- flags(flags),
- keyCode(keyCode),
- scanCode(scanCode),
- metaState(metaState),
- repeatCount(repeatCount),
- downTime(downTime),
- syntheticRepeat(false),
- interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN),
- interceptKeyWakeupTime(0) {}
-
-InputDispatcher::KeyEntry::~KeyEntry() {}
-
-void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const {
- msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, "
- "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
- "repeatCount=%d), policyFlags=0x%08x",
- deviceId, source, displayId, keyActionToString(action).c_str(), flags,
- keyCode, scanCode, metaState, repeatCount, policyFlags);
-}
-
-void InputDispatcher::KeyEntry::recycle() {
- releaseInjectionState();
-
- dispatchInProgress = false;
- syntheticRepeat = false;
- interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
- interceptKeyWakeupTime = 0;
-}
-
-// --- InputDispatcher::MotionEntry ---
-
-InputDispatcher::MotionEntry::MotionEntry(
- uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
- int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, nsecs_t downTime, uint32_t pointerCount,
- const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xOffset, float yOffset)
- : EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags),
- eventTime(eventTime),
- deviceId(deviceId),
- source(source),
- displayId(displayId),
- action(action),
- actionButton(actionButton),
- flags(flags),
- metaState(metaState),
- buttonState(buttonState),
- classification(classification),
- edgeFlags(edgeFlags),
- xPrecision(xPrecision),
- yPrecision(yPrecision),
- xCursorPosition(xCursorPosition),
- yCursorPosition(yCursorPosition),
- downTime(downTime),
- pointerCount(pointerCount) {
- for (uint32_t i = 0; i < pointerCount; i++) {
- this->pointerProperties[i].copyFrom(pointerProperties[i]);
- this->pointerCoords[i].copyFrom(pointerCoords[i]);
- if (xOffset || yOffset) {
- this->pointerCoords[i].applyOffset(xOffset, yOffset);
- }
- }
-}
-
-InputDispatcher::MotionEntry::~MotionEntry() {}
-
-void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
- msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
- ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, "
- "buttonState=0x%08x, "
- "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, "
- "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[",
- deviceId, source, displayId, motionActionToString(action).c_str(),
- actionButton, flags, metaState, buttonState,
- motionClassificationToString(classification), edgeFlags, xPrecision,
- yPrecision, xCursorPosition, yCursorPosition);
-
- for (uint32_t i = 0; i < pointerCount; i++) {
- if (i) {
- msg += ", ";
- }
- msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id, pointerCoords[i].getX(),
- pointerCoords[i].getY());
- }
- msg += StringPrintf("]), policyFlags=0x%08x", policyFlags);
-}
-
-// --- InputDispatcher::DispatchEntry ---
-
-volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic;
-
-InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, int32_t targetFlags,
- float xOffset, float yOffset, float globalScaleFactor,
- float windowXScale, float windowYScale)
- : seq(nextSeq()),
- eventEntry(eventEntry),
- targetFlags(targetFlags),
- xOffset(xOffset),
- yOffset(yOffset),
- globalScaleFactor(globalScaleFactor),
- windowXScale(windowXScale),
- windowYScale(windowYScale),
- deliveryTime(0),
- resolvedAction(0),
- resolvedFlags(0) {
- eventEntry->refCount += 1;
-}
-
-InputDispatcher::DispatchEntry::~DispatchEntry() {
- eventEntry->release();
-}
-
-uint32_t InputDispatcher::DispatchEntry::nextSeq() {
- // Sequence number 0 is reserved and will never be returned.
- uint32_t seq;
- do {
- seq = android_atomic_inc(&sNextSeqAtomic);
- } while (!seq);
- return seq;
-}
-
-// --- InputDispatcher::InputState ---
-
-InputDispatcher::InputState::InputState() {}
-
-InputDispatcher::InputState::~InputState() {}
-
-bool InputDispatcher::InputState::isNeutral() const {
- return mKeyMementos.empty() && mMotionMementos.empty();
-}
-
-bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source,
- int32_t displayId) const {
- for (const MotionMemento& memento : mMotionMementos) {
- if (memento.deviceId == deviceId && memento.source == source &&
- memento.displayId == displayId && memento.hovering) {
- return true;
- }
- }
- return false;
-}
-
-bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action, int32_t flags) {
- switch (action) {
- case AKEY_EVENT_ACTION_UP: {
- if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) {
- for (size_t i = 0; i < mFallbackKeys.size();) {
- if (mFallbackKeys.valueAt(i) == entry->keyCode) {
- mFallbackKeys.removeItemsAt(i);
- } else {
- i += 1;
- }
- }
- }
- ssize_t index = findKeyMemento(entry);
- if (index >= 0) {
- mKeyMementos.erase(mKeyMementos.begin() + index);
- return true;
- }
- /* FIXME: We can't just drop the key up event because that prevents creating
- * popup windows that are automatically shown when a key is held and then
- * dismissed when the key is released. The problem is that the popup will
- * not have received the original key down, so the key up will be considered
- * to be inconsistent with its observed state. We could perhaps handle this
- * by synthesizing a key down but that will cause other problems.
- *
- * So for now, allow inconsistent key up events to be dispatched.
- *
- #if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
- "keyCode=%d, scanCode=%d",
- entry->deviceId, entry->source, entry->keyCode, entry->scanCode);
- #endif
- return false;
- */
- return true;
- }
-
- case AKEY_EVENT_ACTION_DOWN: {
- ssize_t index = findKeyMemento(entry);
- if (index >= 0) {
- mKeyMementos.erase(mKeyMementos.begin() + index);
- }
- addKeyMemento(entry, flags);
- return true;
- }
-
- default:
- return true;
- }
-}
-
-bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, int32_t action,
- int32_t flags) {
- int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
- switch (actionMasked) {
- case AMOTION_EVENT_ACTION_UP:
- case AMOTION_EVENT_ACTION_CANCEL: {
- ssize_t index = findMotionMemento(entry, false /*hovering*/);
- if (index >= 0) {
- mMotionMementos.erase(mMotionMementos.begin() + index);
- return true;
- }
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
- "displayId=%" PRId32 ", actionMasked=%d",
- entry->deviceId, entry->source, entry->displayId, actionMasked);
-#endif
- return false;
- }
-
- case AMOTION_EVENT_ACTION_DOWN: {
- ssize_t index = findMotionMemento(entry, false /*hovering*/);
- if (index >= 0) {
- mMotionMementos.erase(mMotionMementos.begin() + index);
- }
- addMotionMemento(entry, flags, false /*hovering*/);
- return true;
- }
-
- case AMOTION_EVENT_ACTION_POINTER_UP:
- case AMOTION_EVENT_ACTION_POINTER_DOWN:
- case AMOTION_EVENT_ACTION_MOVE: {
- if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) {
- // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
- // to generate cancellation events for these since they're based in relative rather
- // than absolute units.
- return true;
- }
-
- ssize_t index = findMotionMemento(entry, false /*hovering*/);
-
- if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) {
- // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
- // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
- // Any other value and we need to track the motion so we can send cancellation
- // events for anything generating fallback events (e.g. DPad keys for joystick
- // movements).
- if (index >= 0) {
- if (entry->pointerCoords[0].isEmpty()) {
- mMotionMementos.erase(mMotionMementos.begin() + index);
- } else {
- MotionMemento& memento = mMotionMementos[index];
- memento.setPointers(entry);
- }
- } else if (!entry->pointerCoords[0].isEmpty()) {
- addMotionMemento(entry, flags, false /*hovering*/);
- }
-
- // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
- return true;
- }
- if (index >= 0) {
- MotionMemento& memento = mMotionMementos[index];
- memento.setPointers(entry);
- return true;
- }
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Dropping inconsistent motion pointer up/down or move event: "
- "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
- entry->deviceId, entry->source, entry->displayId, actionMasked);
-#endif
- return false;
- }
-
- case AMOTION_EVENT_ACTION_HOVER_EXIT: {
- ssize_t index = findMotionMemento(entry, true /*hovering*/);
- if (index >= 0) {
- mMotionMementos.erase(mMotionMementos.begin() + index);
- return true;
- }
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
- "displayId=%" PRId32,
- entry->deviceId, entry->source, entry->displayId);
-#endif
- return false;
- }
-
- case AMOTION_EVENT_ACTION_HOVER_ENTER:
- case AMOTION_EVENT_ACTION_HOVER_MOVE: {
- ssize_t index = findMotionMemento(entry, true /*hovering*/);
- if (index >= 0) {
- mMotionMementos.erase(mMotionMementos.begin() + index);
- }
- addMotionMemento(entry, flags, true /*hovering*/);
- return true;
- }
-
- default:
- return true;
- }
-}
-
-ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const {
- for (size_t i = 0; i < mKeyMementos.size(); i++) {
- const KeyMemento& memento = mKeyMementos[i];
- if (memento.deviceId == entry->deviceId && memento.source == entry->source &&
- memento.displayId == entry->displayId && memento.keyCode == entry->keyCode &&
- memento.scanCode == entry->scanCode) {
- return i;
- }
- }
- return -1;
-}
-
-ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry,
- bool hovering) const {
- for (size_t i = 0; i < mMotionMementos.size(); i++) {
- const MotionMemento& memento = mMotionMementos[i];
- if (memento.deviceId == entry->deviceId && memento.source == entry->source &&
- memento.displayId == entry->displayId && memento.hovering == hovering) {
- return i;
- }
- }
- return -1;
-}
-
-void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) {
- KeyMemento memento;
- memento.deviceId = entry->deviceId;
- memento.source = entry->source;
- memento.displayId = entry->displayId;
- memento.keyCode = entry->keyCode;
- memento.scanCode = entry->scanCode;
- memento.metaState = entry->metaState;
- memento.flags = flags;
- memento.downTime = entry->downTime;
- memento.policyFlags = entry->policyFlags;
- mKeyMementos.push_back(memento);
-}
-
-void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, int32_t flags,
- bool hovering) {
- MotionMemento memento;
- memento.deviceId = entry->deviceId;
- memento.source = entry->source;
- memento.displayId = entry->displayId;
- memento.flags = flags;
- memento.xPrecision = entry->xPrecision;
- memento.yPrecision = entry->yPrecision;
- memento.xCursorPosition = entry->xCursorPosition;
- memento.yCursorPosition = entry->yCursorPosition;
- memento.downTime = entry->downTime;
- memento.setPointers(entry);
- memento.hovering = hovering;
- memento.policyFlags = entry->policyFlags;
- mMotionMementos.push_back(memento);
-}
-
-void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) {
- pointerCount = entry->pointerCount;
- for (uint32_t i = 0; i < entry->pointerCount; i++) {
- pointerProperties[i].copyFrom(entry->pointerProperties[i]);
- pointerCoords[i].copyFrom(entry->pointerCoords[i]);
- }
-}
-
-void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
- std::vector<EventEntry*>& outEvents,
- const CancelationOptions& options) {
- for (KeyMemento& memento : mKeyMementos) {
- if (shouldCancelKey(memento, options)) {
- outEvents.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
- memento.deviceId, memento.source, memento.displayId,
- memento.policyFlags, AKEY_EVENT_ACTION_UP,
- memento.flags | AKEY_EVENT_FLAG_CANCELED,
- memento.keyCode, memento.scanCode, memento.metaState,
- 0, memento.downTime));
- }
- }
-
- for (const MotionMemento& memento : mMotionMementos) {
- if (shouldCancelMotion(memento, options)) {
- const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
- : AMOTION_EVENT_ACTION_CANCEL;
- outEvents.push_back(
- new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, memento.deviceId,
- memento.source, memento.displayId, memento.policyFlags, action,
- 0 /*actionButton*/, memento.flags, AMETA_NONE,
- 0 /*buttonState*/, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
- memento.yPrecision, memento.xCursorPosition,
- memento.yCursorPosition, memento.downTime, memento.pointerCount,
- memento.pointerProperties, memento.pointerCoords, 0 /*xOffset*/,
- 0 /*yOffset*/));
- }
- }
-}
-
-void InputDispatcher::InputState::clear() {
- mKeyMementos.clear();
- mMotionMementos.clear();
- mFallbackKeys.clear();
-}
-
-void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
- for (size_t i = 0; i < mMotionMementos.size(); i++) {
- const MotionMemento& memento = mMotionMementos[i];
- if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
- for (size_t j = 0; j < other.mMotionMementos.size();) {
- const MotionMemento& otherMemento = other.mMotionMementos[j];
- if (memento.deviceId == otherMemento.deviceId &&
- memento.source == otherMemento.source &&
- memento.displayId == otherMemento.displayId) {
- other.mMotionMementos.erase(other.mMotionMementos.begin() + j);
- } else {
- j += 1;
- }
- }
- other.mMotionMementos.push_back(memento);
- }
- }
-}
-
-int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) {
- ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
- return index >= 0 ? mFallbackKeys.valueAt(index) : -1;
-}
-
-void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) {
- ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
- if (index >= 0) {
- mFallbackKeys.replaceValueAt(index, fallbackKeyCode);
- } else {
- mFallbackKeys.add(originalKeyCode, fallbackKeyCode);
- }
-}
-
-void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) {
- mFallbackKeys.removeItem(originalKeyCode);
-}
-
-bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento,
- const CancelationOptions& options) {
- if (options.keyCode && memento.keyCode != options.keyCode.value()) {
- return false;
- }
-
- if (options.deviceId && memento.deviceId != options.deviceId.value()) {
- return false;
- }
-
- if (options.displayId && memento.displayId != options.displayId.value()) {
- return false;
- }
-
- switch (options.mode) {
- case CancelationOptions::CANCEL_ALL_EVENTS:
- case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
- return true;
- case CancelationOptions::CANCEL_FALLBACK_EVENTS:
- return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
- default:
- return false;
- }
-}
-
-bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento,
- const CancelationOptions& options) {
- if (options.deviceId && memento.deviceId != options.deviceId.value()) {
- return false;
- }
-
- if (options.displayId && memento.displayId != options.displayId.value()) {
- return false;
- }
-
- switch (options.mode) {
- case CancelationOptions::CANCEL_ALL_EVENTS:
- return true;
- case CancelationOptions::CANCEL_POINTER_EVENTS:
- return memento.source & AINPUT_SOURCE_CLASS_POINTER;
- case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
- return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
- default:
- return false;
- }
-}
-
-// --- InputDispatcher::Connection ---
-
-InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor)
- : status(STATUS_NORMAL),
- inputChannel(inputChannel),
- monitor(monitor),
- inputPublisher(inputChannel),
- inputPublisherBlocked(false) {}
-
-InputDispatcher::Connection::~Connection() {}
-
-const std::string InputDispatcher::Connection::getWindowName() const {
- if (inputChannel != nullptr) {
- return inputChannel->getName();
- }
- if (monitor) {
- return "monitor";
- }
- return "?";
-}
-
-const char* InputDispatcher::Connection::getStatusLabel() const {
- switch (status) {
- case STATUS_NORMAL:
- return "NORMAL";
-
- case STATUS_BROKEN:
- return "BROKEN";
-
- case STATUS_ZOMBIE:
- return "ZOMBIE";
-
- default:
- return "UNKNOWN";
- }
-}
-
-std::deque<InputDispatcher::DispatchEntry*>::iterator
-InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
- for (std::deque<DispatchEntry*>::iterator it = waitQueue.begin(); it != waitQueue.end(); it++) {
- if ((*it)->seq == seq) {
- return it;
- }
- }
- return waitQueue.end();
-}
-
-// --- InputDispatcher::Monitor
-InputDispatcher::Monitor::Monitor(const sp<InputChannel>& inputChannel)
- : inputChannel(inputChannel) {}
-
-// --- InputDispatcher::CommandEntry ---
-//
-InputDispatcher::CommandEntry::CommandEntry(Command command)
- : command(command),
- eventTime(0),
- keyEntry(nullptr),
- userActivityEventType(0),
- seq(0),
- handled(false) {}
-
-InputDispatcher::CommandEntry::~CommandEntry() {}
-
-// --- InputDispatcher::TouchedMonitor ---
-InputDispatcher::TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset,
- float yOffset)
- : monitor(monitor), xOffset(xOffset), yOffset(yOffset) {}
-
-// --- InputDispatcher::TouchState ---
-
-InputDispatcher::TouchState::TouchState()
- : down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {}
-
-InputDispatcher::TouchState::~TouchState() {}
-
-void InputDispatcher::TouchState::reset() {
- down = false;
- split = false;
- deviceId = -1;
- source = 0;
- displayId = ADISPLAY_ID_NONE;
- windows.clear();
- portalWindows.clear();
- gestureMonitors.clear();
-}
-
-void InputDispatcher::TouchState::copyFrom(const TouchState& other) {
- down = other.down;
- split = other.split;
- deviceId = other.deviceId;
- source = other.source;
- displayId = other.displayId;
- windows = other.windows;
- portalWindows = other.portalWindows;
- gestureMonitors = other.gestureMonitors;
-}
-
-void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds) {
- if (targetFlags & InputTarget::FLAG_SPLIT) {
- split = true;
- }
-
- for (size_t i = 0; i < windows.size(); i++) {
- TouchedWindow& touchedWindow = windows[i];
- if (touchedWindow.windowHandle == windowHandle) {
- touchedWindow.targetFlags |= targetFlags;
- if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
- touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
- }
- touchedWindow.pointerIds.value |= pointerIds.value;
- return;
- }
- }
-
- TouchedWindow touchedWindow;
- touchedWindow.windowHandle = windowHandle;
- touchedWindow.targetFlags = targetFlags;
- touchedWindow.pointerIds = pointerIds;
- windows.push_back(touchedWindow);
-}
-
-void InputDispatcher::TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) {
- size_t numWindows = portalWindows.size();
- for (size_t i = 0; i < numWindows; i++) {
- if (portalWindows[i] == windowHandle) {
- return;
- }
- }
- portalWindows.push_back(windowHandle);
-}
-
-void InputDispatcher::TouchState::addGestureMonitors(
- const std::vector<TouchedMonitor>& newMonitors) {
- const size_t newSize = gestureMonitors.size() + newMonitors.size();
- gestureMonitors.reserve(newSize);
- gestureMonitors.insert(std::end(gestureMonitors), std::begin(newMonitors),
- std::end(newMonitors));
-}
-
-void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
- for (size_t i = 0; i < windows.size(); i++) {
- if (windows[i].windowHandle == windowHandle) {
- windows.erase(windows.begin() + i);
- return;
- }
- }
-}
-
-void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) {
- for (size_t i = 0; i < windows.size(); i++) {
- if (windows[i].windowHandle->getToken() == token) {
- windows.erase(windows.begin() + i);
- return;
- }
- }
-}
-
-void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
- for (size_t i = 0; i < windows.size();) {
- TouchedWindow& window = windows[i];
- if (window.targetFlags &
- (InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {
- window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
- window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
- i += 1;
- } else {
- windows.erase(windows.begin() + i);
- }
- }
-}
-
-void InputDispatcher::TouchState::filterNonMonitors() {
- windows.clear();
- portalWindows.clear();
-}
-
-sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const {
- for (size_t i = 0; i < windows.size(); i++) {
- const TouchedWindow& window = windows[i];
- if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
- return window.windowHandle;
- }
- }
- return nullptr;
-}
-
-bool InputDispatcher::TouchState::isSlippery() const {
- // Must have exactly one foreground window.
- bool haveSlipperyForegroundWindow = false;
- for (const TouchedWindow& window : windows) {
- if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
- if (haveSlipperyForegroundWindow ||
- !(window.windowHandle->getInfo()->layoutParamsFlags &
- InputWindowInfo::FLAG_SLIPPERY)) {
- return false;
- }
- haveSlipperyForegroundWindow = true;
- }
- }
- return haveSlipperyForegroundWindow;
-}
-
-// --- InputDispatcherThread ---
-
-InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher)
- : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {}
-
-InputDispatcherThread::~InputDispatcherThread() {}
-
-bool InputDispatcherThread::threadLoop() {
- mDispatcher->dispatchOnce();
- return true;
-}
-
-} // namespace android
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index a90f958..f2c0402 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -17,371 +17,42 @@
#ifndef _UI_INPUT_DISPATCHER_H
#define _UI_INPUT_DISPATCHER_H
-#include <cutils/atomic.h>
-#include <input/ISetInputWindowsListener.h>
+#include "CancelationOptions.h"
+#include "Entry.h"
+#include "InjectionState.h"
+#include "InputDispatcherConfiguration.h"
+#include "InputDispatcherInterface.h"
+#include "InputDispatcherPolicyInterface.h"
+#include "InputState.h"
+#include "InputTarget.h"
+#include "Monitor.h"
+#include "TouchState.h"
+#include "TouchedWindow.h"
+
#include <input/Input.h>
#include <input/InputApplication.h>
#include <input/InputTransport.h>
#include <input/InputWindow.h>
+#include <limits.h>
+#include <stddef.h>
#include <ui/Region.h>
+#include <unistd.h>
#include <utils/BitSet.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <utils/threads.h>
#include <condition_variable>
+#include <deque>
#include <optional>
#include <unordered_map>
-#include <limits.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <deque>
-#include <unordered_map>
+#include <InputListener.h>
+#include <InputReporterInterface.h>
-#include "InputListener.h"
-#include "InputReporterInterface.h"
+namespace android::inputdispatcher {
-namespace android {
-
-/*
- * Constants used to report the outcome of input event injection.
- */
-enum {
- /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */
- INPUT_EVENT_INJECTION_PENDING = -1,
-
- /* Injection succeeded. */
- INPUT_EVENT_INJECTION_SUCCEEDED = 0,
-
- /* Injection failed because the injector did not have permission to inject
- * into the application with input focus. */
- INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1,
-
- /* Injection failed because there were no available input targets. */
- INPUT_EVENT_INJECTION_FAILED = 2,
-
- /* Injection failed due to a timeout. */
- INPUT_EVENT_INJECTION_TIMED_OUT = 3
-};
-
-/*
- * Constants used to determine the input event injection synchronization mode.
- */
-enum {
- /* Injection is asynchronous and is assumed always to be successful. */
- INPUT_EVENT_INJECTION_SYNC_NONE = 0,
-
- /* Waits for previous events to be dispatched so that the input dispatcher can determine
- * whether input event injection willbe permitted based on the current input focus.
- * Does not wait for the input event to finish processing. */
- INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1,
-
- /* Waits for the input event to be completely processed. */
- INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2,
-};
-
-/*
- * An input target specifies how an input event is to be dispatched to a particular window
- * including the window's input channel, control flags, a timeout, and an X / Y offset to
- * be added to input event coordinates to compensate for the absolute position of the
- * window area.
- */
-struct InputTarget {
- enum {
- /* This flag indicates that the event is being delivered to a foreground application. */
- FLAG_FOREGROUND = 1 << 0,
-
- /* This flag indicates that the MotionEvent falls within the area of the target
- * obscured by another visible window above it. The motion event should be
- * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
- FLAG_WINDOW_IS_OBSCURED = 1 << 1,
-
- /* This flag indicates that a motion event is being split across multiple windows. */
- FLAG_SPLIT = 1 << 2,
-
- /* This flag indicates that the pointer coordinates dispatched to the application
- * will be zeroed out to avoid revealing information to an application. This is
- * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing
- * the same UID from watching all touches. */
- FLAG_ZERO_COORDS = 1 << 3,
-
- /* This flag indicates that the event should be sent as is.
- * Should always be set unless the event is to be transmuted. */
- FLAG_DISPATCH_AS_IS = 1 << 8,
-
- /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
- * of the area of this target and so should instead be delivered as an
- * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
- FLAG_DISPATCH_AS_OUTSIDE = 1 << 9,
-
- /* This flag indicates that a hover sequence is starting in the given window.
- * The event is transmuted into ACTION_HOVER_ENTER. */
- FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10,
-
- /* This flag indicates that a hover event happened outside of a window which handled
- * previous hover events, signifying the end of the current hover sequence for that
- * window.
- * The event is transmuted into ACTION_HOVER_ENTER. */
- FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11,
-
- /* This flag indicates that the event should be canceled.
- * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips
- * outside of a window. */
- FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12,
-
- /* This flag indicates that the event should be dispatched as an initial down.
- * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips
- * into a new window. */
- FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13,
-
- /* Mask for all dispatch modes. */
- FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE |
- FLAG_DISPATCH_AS_HOVER_ENTER | FLAG_DISPATCH_AS_HOVER_EXIT |
- FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER,
-
- /* This flag indicates that the target of a MotionEvent is partly or wholly
- * obscured by another visible window above it. The motion event should be
- * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
- FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
-
- };
-
- // The input channel to be targeted.
- sp<InputChannel> inputChannel;
-
- // Flags for the input target.
- int32_t flags;
-
- // The x and y offset to add to a MotionEvent as it is delivered.
- // (ignored for KeyEvents)
- float xOffset, yOffset;
-
- // Scaling factor to apply to MotionEvent as it is delivered.
- // (ignored for KeyEvents)
- float globalScaleFactor;
- float windowXScale = 1.0f;
- float windowYScale = 1.0f;
-
- // The subset of pointer ids to include in motion events dispatched to this input target
- // if FLAG_SPLIT is set.
- BitSet32 pointerIds;
-};
-
-/*
- * Input dispatcher configuration.
- *
- * Specifies various options that modify the behavior of the input dispatcher.
- * The values provided here are merely defaults. The actual values will come from ViewConfiguration
- * and are passed into the dispatcher during initialization.
- */
-struct InputDispatcherConfiguration {
- // The key repeat initial timeout.
- nsecs_t keyRepeatTimeout;
-
- // The key repeat inter-key delay.
- nsecs_t keyRepeatDelay;
-
- InputDispatcherConfiguration()
- : keyRepeatTimeout(500 * 1000000LL), keyRepeatDelay(50 * 1000000LL) {}
-};
-
-/*
- * Input dispatcher policy interface.
- *
- * The input reader policy is used by the input reader to interact with the Window Manager
- * and other system components.
- *
- * The actual implementation is partially supported by callbacks into the DVM
- * via JNI. This interface is also mocked in the unit tests.
- */
-class InputDispatcherPolicyInterface : public virtual RefBase {
-protected:
- InputDispatcherPolicyInterface() {}
- virtual ~InputDispatcherPolicyInterface() {}
-
-public:
- /* Notifies the system that a configuration change has occurred. */
- virtual void notifyConfigurationChanged(nsecs_t when) = 0;
-
- /* Notifies the system that an application is not responding.
- * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
- virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token, const std::string& reason) = 0;
-
- /* Notifies the system that an input channel is unrecoverably broken. */
- virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
- virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;
-
- /* Gets the input dispatcher configuration. */
- virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
-
- /* Filters an input event.
- * Return true to dispatch the event unmodified, false to consume the event.
- * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED
- * to injectInputEvent.
- */
- virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0;
-
- /* Intercepts a key event immediately before queueing it.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing such as updating policy flags.
- *
- * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
- * should be dispatched to applications.
- */
- virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0;
-
- /* Intercepts a touch, trackball or other motion event before queueing it.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing such as updating policy flags.
- *
- * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
- * should be dispatched to applications.
- */
- virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
- uint32_t& policyFlags) = 0;
-
- /* Allows the policy a chance to intercept a key before dispatching. */
- virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
- const KeyEvent* keyEvent,
- uint32_t policyFlags) = 0;
-
- /* Allows the policy a chance to perform default processing for an unhandled key.
- * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */
- virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,
- uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;
-
- /* Notifies the policy about switch events.
- */
- virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
- uint32_t policyFlags) = 0;
-
- /* Poke user activity for an event dispatched to a window. */
- virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;
-
- /* Checks whether a given application pid/uid has permission to inject input events
- * into other applications.
- *
- * This method is special in that its implementation promises to be non-reentrant and
- * is safe to call while holding other locks. (Most other methods make no such guarantees!)
- */
- virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
- int32_t injectorUid) = 0;
-
- /* Notifies the policy that a pointer down event has occurred outside the current focused
- * window.
- *
- * The touchedToken passed as an argument is the window that received the input event.
- */
- virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0;
-};
-
-/* Notifies the system about input events generated by the input reader.
- * The dispatcher is expected to be mostly asynchronous. */
-class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface {
-protected:
- InputDispatcherInterface() {}
- virtual ~InputDispatcherInterface() {}
-
-public:
- /* Dumps the state of the input dispatcher.
- *
- * This method may be called on any thread (usually by the input manager). */
- virtual void dump(std::string& dump) = 0;
-
- /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
- virtual void monitor() = 0;
-
- /* Runs a single iteration of the dispatch loop.
- * Nominally processes one queued event, a timeout, or a response from an input consumer.
- *
- * This method should only be called on the input dispatcher thread.
- */
- virtual void dispatchOnce() = 0;
-
- /* Injects an input event and optionally waits for sync.
- * The synchronization mode determines whether the method blocks while waiting for
- * input injection to proceed.
- * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
- *
- * This method may be called on any thread (usually by the input manager).
- */
- virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid,
- int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
- uint32_t policyFlags) = 0;
-
- /* Sets the list of input windows.
- *
- * This method may be called on any thread (usually by the input manager).
- */
- virtual void setInputWindows(
- const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId,
- const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0;
-
- /* Sets the focused application on the given display.
- *
- * This method may be called on any thread (usually by the input manager).
- */
- virtual void setFocusedApplication(
- int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
-
- /* Sets the focused display.
- *
- * This method may be called on any thread (usually by the input manager).
- */
- virtual void setFocusedDisplay(int32_t displayId) = 0;
-
- /* Sets the input dispatching mode.
- *
- * This method may be called on any thread (usually by the input manager).
- */
- virtual void setInputDispatchMode(bool enabled, bool frozen) = 0;
-
- /* Sets whether input event filtering is enabled.
- * When enabled, incoming input events are sent to the policy's filterInputEvent
- * method instead of being dispatched. The filter is expected to use
- * injectInputEvent to inject the events it would like to have dispatched.
- * It should include POLICY_FLAG_FILTERED in the policy flags during injection.
- */
- virtual void setInputFilterEnabled(bool enabled) = 0;
-
- /* Transfers touch focus from one window to another window.
- *
- * Returns true on success. False if the window did not actually have touch focus.
- */
- virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 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).
- */
- virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
- int32_t displayId) = 0;
-
- /* Registers input channels to be used to monitor input events.
- *
- * Each monitor must target a specific display and will only receive input events sent to that
- * display. If the monitor is a gesture monitor, it will only receive pointer events on the
- * targeted display.
- *
- * This method may be called on any thread (usually by the input manager).
- */
- virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId,
- bool gestureMonitor) = 0;
-
- /* Unregister input channels that will no longer receive input events.
- *
- * This method may be called on any thread (usually by the input manager).
- */
- virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
-
- /* Allows an input monitor steal the current pointer stream away from normal input windows.
- *
- * This method may be called on any thread (usually by the input manager).
- */
- virtual status_t pilferPointers(const sp<IBinder>& token) = 0;
-};
+class Connection;
/* Dispatches events to input targets. Some functions of the input dispatcher, such as
* identifying input targets, are controlled by a separate policy object.
@@ -400,7 +71,7 @@
*
* A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa.
*/
-class InputDispatcher : public InputDispatcherInterface {
+class InputDispatcher : public android::InputDispatcherInterface {
protected:
virtual ~InputDispatcher();
@@ -442,376 +113,6 @@
virtual status_t pilferPointers(const sp<IBinder>& token) override;
private:
- struct InjectionState {
- mutable int32_t refCount;
-
- int32_t injectorPid;
- int32_t injectorUid;
- int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING
- bool injectionIsAsync; // set to true if injection is not waiting for the result
- int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
-
- InjectionState(int32_t injectorPid, int32_t injectorUid);
- void release();
-
- private:
- ~InjectionState();
- };
-
- struct EventEntry {
- enum { TYPE_CONFIGURATION_CHANGED, TYPE_DEVICE_RESET, TYPE_KEY, TYPE_MOTION };
-
- uint32_t sequenceNum;
- mutable int32_t refCount;
- int32_t type;
- nsecs_t eventTime;
- uint32_t policyFlags;
- InjectionState* injectionState;
-
- bool dispatchInProgress; // initially false, set to true while dispatching
-
- inline bool isInjected() const { return injectionState != nullptr; }
-
- void release();
-
- virtual void appendDescription(std::string& msg) const = 0;
-
- protected:
- EventEntry(uint32_t sequenceNum, int32_t type, nsecs_t eventTime, uint32_t policyFlags);
- virtual ~EventEntry();
- void releaseInjectionState();
- };
-
- struct ConfigurationChangedEntry : EventEntry {
- explicit ConfigurationChangedEntry(uint32_t sequenceNum, nsecs_t eventTime);
- virtual void appendDescription(std::string& msg) const;
-
- protected:
- virtual ~ConfigurationChangedEntry();
- };
-
- struct DeviceResetEntry : EventEntry {
- int32_t deviceId;
-
- DeviceResetEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId);
- virtual void appendDescription(std::string& msg) const;
-
- protected:
- virtual ~DeviceResetEntry();
- };
-
- struct KeyEntry : EventEntry {
- int32_t deviceId;
- uint32_t source;
- int32_t displayId;
- int32_t action;
- int32_t flags;
- int32_t keyCode;
- int32_t scanCode;
- int32_t metaState;
- int32_t repeatCount;
- nsecs_t downTime;
-
- bool syntheticRepeat; // set to true for synthetic key repeats
-
- enum InterceptKeyResult {
- INTERCEPT_KEY_RESULT_UNKNOWN,
- INTERCEPT_KEY_RESULT_SKIP,
- INTERCEPT_KEY_RESULT_CONTINUE,
- INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER,
- };
- InterceptKeyResult interceptKeyResult; // set based on the interception result
- nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER
-
- KeyEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags,
- int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount,
- nsecs_t downTime);
- virtual void appendDescription(std::string& msg) const;
- void recycle();
-
- protected:
- virtual ~KeyEntry();
- };
-
- struct MotionEntry : EventEntry {
- nsecs_t eventTime;
- int32_t deviceId;
- uint32_t source;
- int32_t displayId;
- int32_t action;
- int32_t actionButton;
- int32_t flags;
- int32_t metaState;
- int32_t buttonState;
- MotionClassification classification;
- int32_t edgeFlags;
- float xPrecision;
- float yPrecision;
- float xCursorPosition;
- float yCursorPosition;
- nsecs_t downTime;
- uint32_t pointerCount;
- PointerProperties pointerProperties[MAX_POINTERS];
- PointerCoords pointerCoords[MAX_POINTERS];
-
- MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
- int32_t flags, int32_t metaState, int32_t buttonState,
- MotionClassification classification, int32_t edgeFlags, float xPrecision,
- float yPrecision, float xCursorPosition, float yCursorPosition,
- nsecs_t downTime, uint32_t pointerCount,
- const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xOffset, float yOffset);
- virtual void appendDescription(std::string& msg) const;
-
- protected:
- virtual ~MotionEntry();
- };
-
- // Tracks the progress of dispatching a particular event to a particular connection.
- struct DispatchEntry {
- const uint32_t seq; // unique sequence number, never 0
-
- EventEntry* eventEntry; // the event to dispatch
- int32_t targetFlags;
- float xOffset;
- float yOffset;
- float globalScaleFactor;
- float windowXScale = 1.0f;
- float windowYScale = 1.0f;
- nsecs_t deliveryTime; // time when the event was actually delivered
-
- // Set to the resolved action and flags when the event is enqueued.
- int32_t resolvedAction;
- int32_t resolvedFlags;
-
- DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, float yOffset,
- float globalScaleFactor, float windowXScale, float windowYScale);
- ~DispatchEntry();
-
- inline bool hasForegroundTarget() const {
- return targetFlags & InputTarget::FLAG_FOREGROUND;
- }
-
- inline bool isSplit() const { return targetFlags & InputTarget::FLAG_SPLIT; }
-
- private:
- static volatile int32_t sNextSeqAtomic;
-
- static uint32_t nextSeq();
- };
-
- // A command entry captures state and behavior for an action to be performed in the
- // dispatch loop after the initial processing has taken place. It is essentially
- // a kind of continuation used to postpone sensitive policy interactions to a point
- // in the dispatch loop where it is safe to release the lock (generally after finishing
- // the critical parts of the dispatch cycle).
- //
- // The special thing about commands is that they can voluntarily release and reacquire
- // the dispatcher lock at will. Initially when the command starts running, the
- // dispatcher lock is held. However, if the command needs to call into the policy to
- // do some work, it can release the lock, do the work, then reacquire the lock again
- // before returning.
- //
- // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
- // never calls into the policy while holding its lock.
- //
- // Commands are implicitly 'LockedInterruptible'.
- struct CommandEntry;
- typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
-
- class Connection;
- struct CommandEntry {
- explicit CommandEntry(Command command);
- ~CommandEntry();
-
- Command command;
-
- // parameters for the command (usage varies by command)
- sp<Connection> connection;
- nsecs_t eventTime;
- KeyEntry* keyEntry;
- sp<InputApplicationHandle> inputApplicationHandle;
- std::string reason;
- int32_t userActivityEventType;
- uint32_t seq;
- bool handled;
- sp<InputChannel> inputChannel;
- sp<IBinder> oldToken;
- sp<IBinder> newToken;
- };
-
- /* Specifies which events are to be canceled and why. */
- struct CancelationOptions {
- enum Mode {
- CANCEL_ALL_EVENTS = 0,
- CANCEL_POINTER_EVENTS = 1,
- CANCEL_NON_POINTER_EVENTS = 2,
- CANCEL_FALLBACK_EVENTS = 3,
- };
-
- // The criterion to use to determine which events should be canceled.
- Mode mode;
-
- // Descriptive reason for the cancelation.
- const char* reason;
-
- // The specific keycode of the key event to cancel, or nullopt to cancel any key event.
- std::optional<int32_t> keyCode = std::nullopt;
-
- // The specific device id of events to cancel, or nullopt to cancel events from any device.
- std::optional<int32_t> deviceId = std::nullopt;
-
- // The specific display id of events to cancel, or nullopt to cancel events on any display.
- std::optional<int32_t> displayId = std::nullopt;
-
- CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) {}
- };
-
- /* Tracks dispatched key and motion event state so that cancelation events can be
- * synthesized when events are dropped. */
- class InputState {
- public:
- InputState();
- ~InputState();
-
- // Returns true if there is no state to be canceled.
- bool isNeutral() const;
-
- // Returns true if the specified source is known to have received a hover enter
- // motion event.
- bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const;
-
- // Records tracking information for a key event that has just been published.
- // Returns true if the event should be delivered, false if it is inconsistent
- // and should be skipped.
- bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags);
-
- // Records tracking information for a motion event that has just been published.
- // Returns true if the event should be delivered, false if it is inconsistent
- // and should be skipped.
- bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags);
-
- // Synthesizes cancelation events for the current state and resets the tracked state.
- void synthesizeCancelationEvents(nsecs_t currentTime, std::vector<EventEntry*>& outEvents,
- const CancelationOptions& options);
-
- // Clears the current state.
- void clear();
-
- // Copies pointer-related parts of the input state to another instance.
- void copyPointerStateTo(InputState& other) const;
-
- // Gets the fallback key associated with a keycode.
- // Returns -1 if none.
- // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy.
- int32_t getFallbackKey(int32_t originalKeyCode);
-
- // Sets the fallback key for a particular keycode.
- void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode);
-
- // Removes the fallback key for a particular keycode.
- void removeFallbackKey(int32_t originalKeyCode);
-
- inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const {
- return mFallbackKeys;
- }
-
- private:
- struct KeyMemento {
- int32_t deviceId;
- uint32_t source;
- int32_t displayId;
- int32_t keyCode;
- int32_t scanCode;
- int32_t metaState;
- int32_t flags;
- nsecs_t downTime;
- uint32_t policyFlags;
- };
-
- struct MotionMemento {
- int32_t deviceId;
- uint32_t source;
- int32_t displayId;
- int32_t flags;
- float xPrecision;
- float yPrecision;
- float xCursorPosition;
- float yCursorPosition;
- nsecs_t downTime;
- uint32_t pointerCount;
- PointerProperties pointerProperties[MAX_POINTERS];
- PointerCoords pointerCoords[MAX_POINTERS];
- bool hovering;
- uint32_t policyFlags;
-
- void setPointers(const MotionEntry* entry);
- };
-
- std::vector<KeyMemento> mKeyMementos;
- std::vector<MotionMemento> mMotionMementos;
- KeyedVector<int32_t, int32_t> mFallbackKeys;
-
- ssize_t findKeyMemento(const KeyEntry* entry) const;
- ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const;
-
- void addKeyMemento(const KeyEntry* entry, int32_t flags);
- void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering);
-
- static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options);
- static bool shouldCancelMotion(const MotionMemento& memento,
- const CancelationOptions& options);
- };
-
- /* Manages the dispatch state associated with a single input channel. */
- class Connection : public RefBase {
- protected:
- virtual ~Connection();
-
- public:
- enum Status {
- // Everything is peachy.
- STATUS_NORMAL,
- // An unrecoverable communication error has occurred.
- STATUS_BROKEN,
- // The input channel has been unregistered.
- STATUS_ZOMBIE
- };
-
- Status status;
- sp<InputChannel> inputChannel; // never null
- bool monitor;
- InputPublisher inputPublisher;
- InputState inputState;
-
- // True if the socket is full and no further events can be published until
- // the application consumes some of the input.
- bool inputPublisherBlocked;
-
- // Queue of events that need to be published to the connection.
- std::deque<DispatchEntry*> outboundQueue;
-
- // Queue of events that have been published to the connection but that have not
- // yet received a "finished" response from the application.
- std::deque<DispatchEntry*> waitQueue;
-
- explicit Connection(const sp<InputChannel>& inputChannel, bool monitor);
-
- inline const std::string getInputChannelName() const { return inputChannel->getName(); }
-
- const std::string getWindowName() const;
- const char* getStatusLabel() const;
-
- std::deque<DispatchEntry*>::iterator findWaitQueueEntry(uint32_t seq);
- };
-
- struct Monitor {
- sp<InputChannel> inputChannel; // never null
-
- explicit Monitor(const sp<InputChannel>& inputChannel);
- };
enum DropReason {
DROP_REASON_NOT_DROPPED = 0,
@@ -823,7 +124,7 @@
};
sp<InputDispatcherPolicyInterface> mPolicy;
- InputDispatcherConfiguration mConfig;
+ android::InputDispatcherConfiguration mConfig;
std::mutex mLock;
@@ -969,53 +270,6 @@
std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay
GUARDED_BY(mLock);
- // Focus tracking for touch.
- struct TouchedWindow {
- sp<InputWindowHandle> windowHandle;
- int32_t targetFlags;
- BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
- };
-
- // For tracking the offsets we need to apply when adding gesture monitor targets.
- struct TouchedMonitor {
- Monitor monitor;
- float xOffset = 0.f;
- float yOffset = 0.f;
-
- explicit TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset);
- };
-
- struct TouchState {
- bool down;
- bool split;
- int32_t deviceId; // id of the device that is currently down, others are rejected
- uint32_t source; // source of the device that is current down, others are rejected
- int32_t displayId; // id to the display that currently has a touch, others are rejected
- std::vector<TouchedWindow> windows;
-
- // This collects the portal windows that the touch has gone through. Each portal window
- // targets a display (embedded display for most cases). With this info, we can add the
- // monitoring channels of the displays touched.
- std::vector<sp<InputWindowHandle>> portalWindows;
-
- std::vector<TouchedMonitor> gestureMonitors;
-
- TouchState();
- ~TouchState();
- void reset();
- void copyFrom(const TouchState& other);
- void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags,
- BitSet32 pointerIds);
- void addPortalWindow(const sp<InputWindowHandle>& windowHandle);
- void addGestureMonitors(const std::vector<TouchedMonitor>& monitors);
- void removeWindow(const sp<InputWindowHandle>& windowHandle);
- void removeWindowByToken(const sp<IBinder>& token);
- void filterNonAsIsTouchWindows();
- void filterNonMonitors();
- sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
- bool isSlippery() const;
- };
-
KeyedVector<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock);
TouchState mTempTouchState GUARDED_BY(mLock);
@@ -1210,18 +464,6 @@
sp<InputReporterInterface> mReporter;
};
-/* Enqueues and dispatches input events, endlessly. */
-class InputDispatcherThread : public Thread {
-public:
- explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);
- ~InputDispatcherThread();
-
-private:
- virtual bool threadLoop();
-
- sp<InputDispatcherInterface> mDispatcher;
-};
-
-} // namespace android
+} // namespace android::inputdispatcher
#endif // _UI_INPUT_DISPATCHER_H
diff --git a/services/inputflinger/dispatcher/InputDispatcherFactory.cpp b/services/inputflinger/dispatcher/InputDispatcherFactory.cpp
new file mode 100644
index 0000000..8d7fa75
--- /dev/null
+++ b/services/inputflinger/dispatcher/InputDispatcherFactory.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InputDispatcherFactory.h"
+#include "InputDispatcher.h"
+
+namespace android {
+
+sp<InputDispatcherInterface> createInputDispatcher(
+ const sp<InputDispatcherPolicyInterface>& policy) {
+ return new android::inputdispatcher::InputDispatcher(policy);
+}
+
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcherThread.cpp b/services/inputflinger/dispatcher/InputDispatcherThread.cpp
new file mode 100644
index 0000000..18b1b8c
--- /dev/null
+++ b/services/inputflinger/dispatcher/InputDispatcherThread.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InputDispatcherThread.h"
+
+#include "InputDispatcherInterface.h"
+
+namespace android {
+
+InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher)
+ : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {}
+
+InputDispatcherThread::~InputDispatcherThread() {}
+
+bool InputDispatcherThread::threadLoop() {
+ mDispatcher->dispatchOnce();
+ return true;
+}
+
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
new file mode 100644
index 0000000..c60700e
--- /dev/null
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InputState.h"
+
+namespace android::inputdispatcher {
+
+InputState::InputState() {}
+
+InputState::~InputState() {}
+
+bool InputState::isNeutral() const {
+ return mKeyMementos.empty() && mMotionMementos.empty();
+}
+
+bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const {
+ for (const MotionMemento& memento : mMotionMementos) {
+ if (memento.deviceId == deviceId && memento.source == source &&
+ memento.displayId == displayId && memento.hovering) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool InputState::trackKey(const KeyEntry* entry, int32_t action, int32_t flags) {
+ switch (action) {
+ case AKEY_EVENT_ACTION_UP: {
+ if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) {
+ for (size_t i = 0; i < mFallbackKeys.size();) {
+ if (mFallbackKeys.valueAt(i) == entry->keyCode) {
+ mFallbackKeys.removeItemsAt(i);
+ } else {
+ i += 1;
+ }
+ }
+ }
+ ssize_t index = findKeyMemento(entry);
+ if (index >= 0) {
+ mKeyMementos.erase(mKeyMementos.begin() + index);
+ return true;
+ }
+ /* FIXME: We can't just drop the key up event because that prevents creating
+ * popup windows that are automatically shown when a key is held and then
+ * dismissed when the key is released. The problem is that the popup will
+ * not have received the original key down, so the key up will be considered
+ * to be inconsistent with its observed state. We could perhaps handle this
+ * by synthesizing a key down but that will cause other problems.
+ *
+ * So for now, allow inconsistent key up events to be dispatched.
+ *
+ #if DEBUG_OUTBOUND_EVENT_DETAILS
+ ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
+ "keyCode=%d, scanCode=%d",
+ entry->deviceId, entry->source, entry->keyCode, entry->scanCode);
+ #endif
+ return false;
+ */
+ return true;
+ }
+
+ case AKEY_EVENT_ACTION_DOWN: {
+ ssize_t index = findKeyMemento(entry);
+ if (index >= 0) {
+ mKeyMementos.erase(mKeyMementos.begin() + index);
+ }
+ addKeyMemento(entry, flags);
+ return true;
+ }
+
+ default:
+ return true;
+ }
+}
+
+bool InputState::trackMotion(const MotionEntry* entry, int32_t action, int32_t flags) {
+ int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
+ switch (actionMasked) {
+ case AMOTION_EVENT_ACTION_UP:
+ case AMOTION_EVENT_ACTION_CANCEL: {
+ ssize_t index = findMotionMemento(entry, false /*hovering*/);
+ if (index >= 0) {
+ mMotionMementos.erase(mMotionMementos.begin() + index);
+ return true;
+ }
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
+ "displayId=%" PRId32 ", actionMasked=%d",
+ entry->deviceId, entry->source, entry->displayId, actionMasked);
+#endif
+ return false;
+ }
+
+ case AMOTION_EVENT_ACTION_DOWN: {
+ ssize_t index = findMotionMemento(entry, false /*hovering*/);
+ if (index >= 0) {
+ mMotionMementos.erase(mMotionMementos.begin() + index);
+ }
+ addMotionMemento(entry, flags, false /*hovering*/);
+ return true;
+ }
+
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
+ case AMOTION_EVENT_ACTION_MOVE: {
+ if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) {
+ // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need
+ // to generate cancellation events for these since they're based in relative rather
+ // than absolute units.
+ return true;
+ }
+
+ ssize_t index = findMotionMemento(entry, false /*hovering*/);
+
+ if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) {
+ // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
+ // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral.
+ // Any other value and we need to track the motion so we can send cancellation
+ // events for anything generating fallback events (e.g. DPad keys for joystick
+ // movements).
+ if (index >= 0) {
+ if (entry->pointerCoords[0].isEmpty()) {
+ mMotionMementos.erase(mMotionMementos.begin() + index);
+ } else {
+ MotionMemento& memento = mMotionMementos[index];
+ memento.setPointers(entry);
+ }
+ } else if (!entry->pointerCoords[0].isEmpty()) {
+ addMotionMemento(entry, flags, false /*hovering*/);
+ }
+
+ // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
+ return true;
+ }
+ if (index >= 0) {
+ MotionMemento& memento = mMotionMementos[index];
+ memento.setPointers(entry);
+ return true;
+ }
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ ALOGD("Dropping inconsistent motion pointer up/down or move event: "
+ "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
+ entry->deviceId, entry->source, entry->displayId, actionMasked);
+#endif
+ return false;
+ }
+
+ case AMOTION_EVENT_ACTION_HOVER_EXIT: {
+ ssize_t index = findMotionMemento(entry, true /*hovering*/);
+ if (index >= 0) {
+ mMotionMementos.erase(mMotionMementos.begin() + index);
+ return true;
+ }
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
+ "displayId=%" PRId32,
+ entry->deviceId, entry->source, entry->displayId);
+#endif
+ return false;
+ }
+
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE: {
+ ssize_t index = findMotionMemento(entry, true /*hovering*/);
+ if (index >= 0) {
+ mMotionMementos.erase(mMotionMementos.begin() + index);
+ }
+ addMotionMemento(entry, flags, true /*hovering*/);
+ return true;
+ }
+
+ default:
+ return true;
+ }
+}
+
+ssize_t InputState::findKeyMemento(const KeyEntry* entry) const {
+ for (size_t i = 0; i < mKeyMementos.size(); i++) {
+ const KeyMemento& memento = mKeyMementos[i];
+ if (memento.deviceId == entry->deviceId && memento.source == entry->source &&
+ memento.displayId == entry->displayId && memento.keyCode == entry->keyCode &&
+ memento.scanCode == entry->scanCode) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+ssize_t InputState::findMotionMemento(const MotionEntry* entry, bool hovering) const {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ const MotionMemento& memento = mMotionMementos[i];
+ if (memento.deviceId == entry->deviceId && memento.source == entry->source &&
+ memento.displayId == entry->displayId && memento.hovering == hovering) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) {
+ KeyMemento memento;
+ memento.deviceId = entry->deviceId;
+ memento.source = entry->source;
+ memento.displayId = entry->displayId;
+ memento.keyCode = entry->keyCode;
+ memento.scanCode = entry->scanCode;
+ memento.metaState = entry->metaState;
+ memento.flags = flags;
+ memento.downTime = entry->downTime;
+ memento.policyFlags = entry->policyFlags;
+ mKeyMementos.push_back(memento);
+}
+
+void InputState::addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering) {
+ MotionMemento memento;
+ memento.deviceId = entry->deviceId;
+ memento.source = entry->source;
+ memento.displayId = entry->displayId;
+ memento.flags = flags;
+ memento.xPrecision = entry->xPrecision;
+ memento.yPrecision = entry->yPrecision;
+ memento.xCursorPosition = entry->xCursorPosition;
+ memento.yCursorPosition = entry->yCursorPosition;
+ memento.downTime = entry->downTime;
+ memento.setPointers(entry);
+ memento.hovering = hovering;
+ memento.policyFlags = entry->policyFlags;
+ mMotionMementos.push_back(memento);
+}
+
+void InputState::MotionMemento::setPointers(const MotionEntry* entry) {
+ pointerCount = entry->pointerCount;
+ for (uint32_t i = 0; i < entry->pointerCount; i++) {
+ pointerProperties[i].copyFrom(entry->pointerProperties[i]);
+ pointerCoords[i].copyFrom(entry->pointerCoords[i]);
+ }
+}
+
+void InputState::synthesizeCancelationEvents(nsecs_t currentTime,
+ std::vector<EventEntry*>& outEvents,
+ const CancelationOptions& options) {
+ for (KeyMemento& memento : mKeyMementos) {
+ if (shouldCancelKey(memento, options)) {
+ outEvents.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
+ memento.deviceId, memento.source, memento.displayId,
+ memento.policyFlags, AKEY_EVENT_ACTION_UP,
+ memento.flags | AKEY_EVENT_FLAG_CANCELED,
+ memento.keyCode, memento.scanCode, memento.metaState,
+ 0, memento.downTime));
+ }
+ }
+
+ for (const MotionMemento& memento : mMotionMementos) {
+ if (shouldCancelMotion(memento, options)) {
+ const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
+ : AMOTION_EVENT_ACTION_CANCEL;
+ outEvents.push_back(
+ new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, memento.deviceId,
+ memento.source, memento.displayId, memento.policyFlags, action,
+ 0 /*actionButton*/, memento.flags, AMETA_NONE,
+ 0 /*buttonState*/, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+ memento.yPrecision, memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime, memento.pointerCount,
+ memento.pointerProperties, memento.pointerCoords, 0 /*xOffset*/,
+ 0 /*yOffset*/));
+ }
+ }
+}
+
+void InputState::clear() {
+ mKeyMementos.clear();
+ mMotionMementos.clear();
+ mFallbackKeys.clear();
+}
+
+void InputState::copyPointerStateTo(InputState& other) const {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ const MotionMemento& memento = mMotionMementos[i];
+ if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
+ for (size_t j = 0; j < other.mMotionMementos.size();) {
+ const MotionMemento& otherMemento = other.mMotionMementos[j];
+ if (memento.deviceId == otherMemento.deviceId &&
+ memento.source == otherMemento.source &&
+ memento.displayId == otherMemento.displayId) {
+ other.mMotionMementos.erase(other.mMotionMementos.begin() + j);
+ } else {
+ j += 1;
+ }
+ }
+ other.mMotionMementos.push_back(memento);
+ }
+ }
+}
+
+int32_t InputState::getFallbackKey(int32_t originalKeyCode) {
+ ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
+ return index >= 0 ? mFallbackKeys.valueAt(index) : -1;
+}
+
+void InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) {
+ ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode);
+ if (index >= 0) {
+ mFallbackKeys.replaceValueAt(index, fallbackKeyCode);
+ } else {
+ mFallbackKeys.add(originalKeyCode, fallbackKeyCode);
+ }
+}
+
+void InputState::removeFallbackKey(int32_t originalKeyCode) {
+ mFallbackKeys.removeItem(originalKeyCode);
+}
+
+bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {
+ if (options.keyCode && memento.keyCode != options.keyCode.value()) {
+ return false;
+ }
+
+ if (options.deviceId && memento.deviceId != options.deviceId.value()) {
+ return false;
+ }
+
+ if (options.displayId && memento.displayId != options.displayId.value()) {
+ return false;
+ }
+
+ switch (options.mode) {
+ case CancelationOptions::CANCEL_ALL_EVENTS:
+ case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
+ return true;
+ case CancelationOptions::CANCEL_FALLBACK_EVENTS:
+ return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
+ default:
+ return false;
+ }
+}
+
+bool InputState::shouldCancelMotion(const MotionMemento& memento,
+ const CancelationOptions& options) {
+ if (options.deviceId && memento.deviceId != options.deviceId.value()) {
+ return false;
+ }
+
+ if (options.displayId && memento.displayId != options.displayId.value()) {
+ return false;
+ }
+
+ switch (options.mode) {
+ case CancelationOptions::CANCEL_ALL_EVENTS:
+ return true;
+ case CancelationOptions::CANCEL_POINTER_EVENTS:
+ return memento.source & AINPUT_SOURCE_CLASS_POINTER;
+ case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
+ return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
+ default:
+ return false;
+ }
+}
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
new file mode 100644
index 0000000..bccef0f
--- /dev/null
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H
+#define _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H
+
+#include "CancelationOptions.h"
+#include "Entry.h"
+
+#include <utils/Timers.h>
+
+namespace android::inputdispatcher {
+
+// Sequence number for synthesized or injected events.
+constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0;
+
+/* Tracks dispatched key and motion event state so that cancellation events can be
+ * synthesized when events are dropped. */
+class InputState {
+public:
+ InputState();
+ ~InputState();
+
+ // Returns true if there is no state to be canceled.
+ bool isNeutral() const;
+
+ // Returns true if the specified source is known to have received a hover enter
+ // motion event.
+ bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const;
+
+ // Records tracking information for a key event that has just been published.
+ // Returns true if the event should be delivered, false if it is inconsistent
+ // and should be skipped.
+ bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags);
+
+ // Records tracking information for a motion event that has just been published.
+ // Returns true if the event should be delivered, false if it is inconsistent
+ // and should be skipped.
+ bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags);
+
+ // Synthesizes cancelation events for the current state and resets the tracked state.
+ void synthesizeCancelationEvents(nsecs_t currentTime, std::vector<EventEntry*>& outEvents,
+ const CancelationOptions& options);
+
+ // Clears the current state.
+ void clear();
+
+ // Copies pointer-related parts of the input state to another instance.
+ void copyPointerStateTo(InputState& other) const;
+
+ // Gets the fallback key associated with a keycode.
+ // Returns -1 if none.
+ // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy.
+ int32_t getFallbackKey(int32_t originalKeyCode);
+
+ // Sets the fallback key for a particular keycode.
+ void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode);
+
+ // Removes the fallback key for a particular keycode.
+ void removeFallbackKey(int32_t originalKeyCode);
+
+ inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const { return mFallbackKeys; }
+
+private:
+ struct KeyMemento {
+ int32_t deviceId;
+ uint32_t source;
+ int32_t displayId;
+ int32_t keyCode;
+ int32_t scanCode;
+ int32_t metaState;
+ int32_t flags;
+ nsecs_t downTime;
+ uint32_t policyFlags;
+ };
+
+ struct MotionMemento {
+ int32_t deviceId;
+ uint32_t source;
+ int32_t displayId;
+ int32_t flags;
+ float xPrecision;
+ float yPrecision;
+ float xCursorPosition;
+ float yCursorPosition;
+ nsecs_t downTime;
+ uint32_t pointerCount;
+ PointerProperties pointerProperties[MAX_POINTERS];
+ PointerCoords pointerCoords[MAX_POINTERS];
+ bool hovering;
+ uint32_t policyFlags;
+
+ void setPointers(const MotionEntry* entry);
+ };
+
+ std::vector<KeyMemento> mKeyMementos;
+ std::vector<MotionMemento> mMotionMementos;
+ KeyedVector<int32_t, int32_t> mFallbackKeys;
+
+ ssize_t findKeyMemento(const KeyEntry* entry) const;
+ ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const;
+
+ void addKeyMemento(const KeyEntry* entry, int32_t flags);
+ void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering);
+
+ static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options);
+ static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options);
+};
+
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
new file mode 100644
index 0000000..80fa2cb
--- /dev/null
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InputTarget.h"
+
+#include <android-base/stringprintf.h>
+#include <inttypes.h>
+#include <string>
+
+using android::base::StringPrintf;
+
+namespace android::inputdispatcher {
+
+std::string dispatchModeToString(int32_t dispatchMode) {
+ switch (dispatchMode) {
+ case InputTarget::FLAG_DISPATCH_AS_IS:
+ return "DISPATCH_AS_IS";
+ case InputTarget::FLAG_DISPATCH_AS_OUTSIDE:
+ return "DISPATCH_AS_OUTSIDE";
+ case InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER:
+ return "DISPATCH_AS_HOVER_ENTER";
+ case InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT:
+ return "DISPATCH_AS_HOVER_EXIT";
+ case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT:
+ return "DISPATCH_AS_SLIPPERY_EXIT";
+ case InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER:
+ return "DISPATCH_AS_SLIPPERY_ENTER";
+ }
+ return StringPrintf("%" PRId32, dispatchMode);
+}
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
new file mode 100644
index 0000000..5acf92b
--- /dev/null
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H
+#define _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H
+
+#include <input/InputTransport.h>
+#include <utils/BitSet.h>
+#include <utils/RefBase.h>
+
+namespace android::inputdispatcher {
+
+/*
+ * An input target specifies how an input event is to be dispatched to a particular window
+ * including the window's input channel, control flags, a timeout, and an X / Y offset to
+ * be added to input event coordinates to compensate for the absolute position of the
+ * window area.
+ */
+struct InputTarget {
+ enum {
+ /* This flag indicates that the event is being delivered to a foreground application. */
+ FLAG_FOREGROUND = 1 << 0,
+
+ /* This flag indicates that the MotionEvent falls within the area of the target
+ * obscured by another visible window above it. The motion event should be
+ * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
+ FLAG_WINDOW_IS_OBSCURED = 1 << 1,
+
+ /* This flag indicates that a motion event is being split across multiple windows. */
+ FLAG_SPLIT = 1 << 2,
+
+ /* This flag indicates that the pointer coordinates dispatched to the application
+ * will be zeroed out to avoid revealing information to an application. This is
+ * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing
+ * the same UID from watching all touches. */
+ FLAG_ZERO_COORDS = 1 << 3,
+
+ /* This flag indicates that the event should be sent as is.
+ * Should always be set unless the event is to be transmuted. */
+ FLAG_DISPATCH_AS_IS = 1 << 8,
+
+ /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
+ * of the area of this target and so should instead be delivered as an
+ * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
+ FLAG_DISPATCH_AS_OUTSIDE = 1 << 9,
+
+ /* This flag indicates that a hover sequence is starting in the given window.
+ * The event is transmuted into ACTION_HOVER_ENTER. */
+ FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10,
+
+ /* This flag indicates that a hover event happened outside of a window which handled
+ * previous hover events, signifying the end of the current hover sequence for that
+ * window.
+ * The event is transmuted into ACTION_HOVER_ENTER. */
+ FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11,
+
+ /* This flag indicates that the event should be canceled.
+ * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips
+ * outside of a window. */
+ FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12,
+
+ /* This flag indicates that the event should be dispatched as an initial down.
+ * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips
+ * into a new window. */
+ FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13,
+
+ /* Mask for all dispatch modes. */
+ FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE |
+ FLAG_DISPATCH_AS_HOVER_ENTER | FLAG_DISPATCH_AS_HOVER_EXIT |
+ FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER,
+
+ /* This flag indicates that the target of a MotionEvent is partly or wholly
+ * obscured by another visible window above it. The motion event should be
+ * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
+ FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
+
+ };
+
+ // The input channel to be targeted.
+ sp<InputChannel> inputChannel;
+
+ // Flags for the input target.
+ int32_t flags;
+
+ // The x and y offset to add to a MotionEvent as it is delivered.
+ // (ignored for KeyEvents)
+ float xOffset, yOffset;
+
+ // Scaling factor to apply to MotionEvent as it is delivered.
+ // (ignored for KeyEvents)
+ float globalScaleFactor;
+ float windowXScale = 1.0f;
+ float windowYScale = 1.0f;
+
+ // The subset of pointer ids to include in motion events dispatched to this input target
+ // if FLAG_SPLIT is set.
+ BitSet32 pointerIds;
+};
+
+std::string dispatchModeToString(int32_t dispatchMode);
+
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H
diff --git a/services/inputflinger/dispatcher/Monitor.cpp b/services/inputflinger/dispatcher/Monitor.cpp
new file mode 100644
index 0000000..289b084
--- /dev/null
+++ b/services/inputflinger/dispatcher/Monitor.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Monitor.h"
+
+namespace android::inputdispatcher {
+
+// --- Monitor ---
+Monitor::Monitor(const sp<InputChannel>& inputChannel) : inputChannel(inputChannel) {}
+
+// --- TouchedMonitor ---
+TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset)
+ : monitor(monitor), xOffset(xOffset), yOffset(yOffset) {}
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h
new file mode 100644
index 0000000..b67c9eb
--- /dev/null
+++ b/services/inputflinger/dispatcher/Monitor.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_MONITOR_H
+#define _UI_INPUT_INPUTDISPATCHER_MONITOR_H
+
+#include <input/InputTransport.h>
+
+namespace android::inputdispatcher {
+
+struct Monitor {
+ sp<InputChannel> inputChannel; // never null
+
+ explicit Monitor(const sp<InputChannel>& inputChannel);
+};
+
+// For tracking the offsets we need to apply when adding gesture monitor targets.
+struct TouchedMonitor {
+ Monitor monitor;
+ float xOffset = 0.f;
+ float yOffset = 0.f;
+
+ explicit TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset);
+};
+
+} // namespace android::inputdispatcher
+
+#endif // _UI_INPUT_INPUTDISPATCHER_MONITOR_H
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
new file mode 100644
index 0000000..18848a0
--- /dev/null
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/InputWindow.h>
+
+#include "InputTarget.h"
+
+#include "TouchState.h"
+
+using android::InputWindowHandle;
+
+namespace android::inputdispatcher {
+
+TouchState::TouchState()
+ : down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {}
+
+TouchState::~TouchState() {}
+
+void TouchState::reset() {
+ down = false;
+ split = false;
+ deviceId = -1;
+ source = 0;
+ displayId = ADISPLAY_ID_NONE;
+ windows.clear();
+ portalWindows.clear();
+ gestureMonitors.clear();
+}
+
+void TouchState::copyFrom(const TouchState& other) {
+ down = other.down;
+ split = other.split;
+ deviceId = other.deviceId;
+ source = other.source;
+ displayId = other.displayId;
+ windows = other.windows;
+ portalWindows = other.portalWindows;
+ gestureMonitors = other.gestureMonitors;
+}
+
+void TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags,
+ BitSet32 pointerIds) {
+ if (targetFlags & InputTarget::FLAG_SPLIT) {
+ split = true;
+ }
+
+ for (size_t i = 0; i < windows.size(); i++) {
+ TouchedWindow& touchedWindow = windows[i];
+ if (touchedWindow.windowHandle == windowHandle) {
+ touchedWindow.targetFlags |= targetFlags;
+ if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
+ touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
+ }
+ touchedWindow.pointerIds.value |= pointerIds.value;
+ return;
+ }
+ }
+
+ TouchedWindow touchedWindow;
+ touchedWindow.windowHandle = windowHandle;
+ touchedWindow.targetFlags = targetFlags;
+ touchedWindow.pointerIds = pointerIds;
+ windows.push_back(touchedWindow);
+}
+
+void TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) {
+ size_t numWindows = portalWindows.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ if (portalWindows[i] == windowHandle) {
+ return;
+ }
+ }
+ portalWindows.push_back(windowHandle);
+}
+
+void TouchState::addGestureMonitors(const std::vector<TouchedMonitor>& newMonitors) {
+ const size_t newSize = gestureMonitors.size() + newMonitors.size();
+ gestureMonitors.reserve(newSize);
+ gestureMonitors.insert(std::end(gestureMonitors), std::begin(newMonitors),
+ std::end(newMonitors));
+}
+
+void TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
+ for (size_t i = 0; i < windows.size(); i++) {
+ if (windows[i].windowHandle == windowHandle) {
+ windows.erase(windows.begin() + i);
+ return;
+ }
+ }
+}
+
+void TouchState::removeWindowByToken(const sp<IBinder>& token) {
+ for (size_t i = 0; i < windows.size(); i++) {
+ if (windows[i].windowHandle->getToken() == token) {
+ windows.erase(windows.begin() + i);
+ return;
+ }
+ }
+}
+
+void TouchState::filterNonAsIsTouchWindows() {
+ for (size_t i = 0; i < windows.size();) {
+ TouchedWindow& window = windows[i];
+ if (window.targetFlags &
+ (InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {
+ window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
+ window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
+ i += 1;
+ } else {
+ windows.erase(windows.begin() + i);
+ }
+ }
+}
+
+void TouchState::filterNonMonitors() {
+ windows.clear();
+ portalWindows.clear();
+}
+
+sp<InputWindowHandle> TouchState::getFirstForegroundWindowHandle() const {
+ for (size_t i = 0; i < windows.size(); i++) {
+ const TouchedWindow& window = windows[i];
+ if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ return window.windowHandle;
+ }
+ }
+ return nullptr;
+}
+
+bool TouchState::isSlippery() const {
+ // Must have exactly one foreground window.
+ bool haveSlipperyForegroundWindow = false;
+ for (const TouchedWindow& window : windows) {
+ if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
+ if (haveSlipperyForegroundWindow ||
+ !(window.windowHandle->getInfo()->layoutParamsFlags &
+ InputWindowInfo::FLAG_SLIPPERY)) {
+ return false;
+ }
+ haveSlipperyForegroundWindow = true;
+ }
+ }
+ return haveSlipperyForegroundWindow;
+}
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
new file mode 100644
index 0000000..3e0e0eb
--- /dev/null
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H
+#define _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H
+
+#include "Monitor.h"
+#include "TouchedWindow.h"
+
+namespace android {
+
+class InputWindowHandle;
+
+namespace inputdispatcher {
+
+struct TouchState {
+ bool down;
+ bool split;
+ int32_t deviceId; // id of the device that is currently down, others are rejected
+ uint32_t source; // source of the device that is current down, others are rejected
+ int32_t displayId; // id to the display that currently has a touch, others are rejected
+ std::vector<TouchedWindow> windows;
+
+ // This collects the portal windows that the touch has gone through. Each portal window
+ // targets a display (embedded display for most cases). With this info, we can add the
+ // monitoring channels of the displays touched.
+ std::vector<sp<android::InputWindowHandle>> portalWindows;
+
+ std::vector<TouchedMonitor> gestureMonitors;
+
+ TouchState();
+ ~TouchState();
+ void reset();
+ void copyFrom(const TouchState& other);
+ void addOrUpdateWindow(const sp<android::InputWindowHandle>& windowHandle, int32_t targetFlags,
+ BitSet32 pointerIds);
+ void addPortalWindow(const sp<android::InputWindowHandle>& windowHandle);
+ void addGestureMonitors(const std::vector<TouchedMonitor>& monitors);
+ void removeWindow(const sp<android::InputWindowHandle>& windowHandle);
+ void removeWindowByToken(const sp<IBinder>& token);
+ void filterNonAsIsTouchWindows();
+ void filterNonMonitors();
+ sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
+ bool isSlippery() const;
+};
+
+} // namespace inputdispatcher
+} // namespace android
+
+#endif // _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
new file mode 100644
index 0000000..8713aa3
--- /dev/null
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H
+#define _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H
+
+namespace android {
+
+class InputWindowHandle;
+
+namespace inputdispatcher {
+
+// Focus tracking for touch.
+struct TouchedWindow {
+ sp<android::InputWindowHandle> windowHandle;
+ int32_t targetFlags;
+ BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
+};
+
+} // namespace inputdispatcher
+} // namespace android
+
+#endif // _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h
new file mode 100644
index 0000000..00abf47
--- /dev/null
+++ b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H
+#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H
+
+#include <utils/Timers.h>
+
+namespace android {
+
+/*
+ * Input dispatcher configuration.
+ *
+ * Specifies various options that modify the behavior of the input dispatcher.
+ * The values provided here are merely defaults. The actual values will come from ViewConfiguration
+ * and are passed into the dispatcher during initialization.
+ */
+struct InputDispatcherConfiguration {
+ // The key repeat initial timeout.
+ nsecs_t keyRepeatTimeout;
+
+ // The key repeat inter-key delay.
+ nsecs_t keyRepeatDelay;
+
+ InputDispatcherConfiguration()
+ : keyRepeatTimeout(500 * 1000000LL), keyRepeatDelay(50 * 1000000LL) {}
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherFactory.h b/services/inputflinger/dispatcher/include/InputDispatcherFactory.h
new file mode 100644
index 0000000..a359557
--- /dev/null
+++ b/services/inputflinger/dispatcher/include/InputDispatcherFactory.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H
+#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H
+
+#include <utils/RefBase.h>
+
+#include "InputDispatcherInterface.h"
+#include "InputDispatcherPolicyInterface.h"
+
+namespace android {
+
+// This factory method is used to encapsulate implementation details in internal header files.
+sp<InputDispatcherInterface> createInputDispatcher(
+ const sp<InputDispatcherPolicyInterface>& policy);
+
+} // namespace android
+
+#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
new file mode 100644
index 0000000..9329ca6
--- /dev/null
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
+#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
+
+#include <InputListener.h>
+#include <input/ISetInputWindowsListener.h>
+
+namespace android {
+
+class InputApplicationHandle;
+class InputChannel;
+class InputWindowHandle;
+
+/*
+ * Constants used to report the outcome of input event injection.
+ */
+enum {
+ /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */
+ INPUT_EVENT_INJECTION_PENDING = -1,
+
+ /* Injection succeeded. */
+ INPUT_EVENT_INJECTION_SUCCEEDED = 0,
+
+ /* Injection failed because the injector did not have permission to inject
+ * into the application with input focus. */
+ INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1,
+
+ /* Injection failed because there were no available input targets. */
+ INPUT_EVENT_INJECTION_FAILED = 2,
+
+ /* Injection failed due to a timeout. */
+ INPUT_EVENT_INJECTION_TIMED_OUT = 3
+};
+
+/* Notifies the system about input events generated by the input reader.
+ * The dispatcher is expected to be mostly asynchronous. */
+class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface {
+protected:
+ InputDispatcherInterface() {}
+ virtual ~InputDispatcherInterface() {}
+
+public:
+ /* Dumps the state of the input dispatcher.
+ *
+ * This method may be called on any thread (usually by the input manager). */
+ virtual void dump(std::string& dump) = 0;
+
+ /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
+ virtual void monitor() = 0;
+
+ /* Runs a single iteration of the dispatch loop.
+ * Nominally processes one queued event, a timeout, or a response from an input consumer.
+ *
+ * This method should only be called on the input dispatcher thread.
+ */
+ virtual void dispatchOnce() = 0;
+
+ /* Injects an input event and optionally waits for sync.
+ * The synchronization mode determines whether the method blocks while waiting for
+ * input injection to proceed.
+ * Returns one of the INPUT_EVENT_INJECTION_XXX constants.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid,
+ int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
+ uint32_t policyFlags) = 0;
+
+ /* Sets the list of input windows.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual void setInputWindows(
+ const std::vector<sp<InputWindowHandle> >& inputWindowHandles, int32_t displayId,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0;
+
+ /* Sets the focused application on the given display.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual void setFocusedApplication(
+ int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
+
+ /* Sets the focused display.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual void setFocusedDisplay(int32_t displayId) = 0;
+
+ /* Sets the input dispatching mode.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual void setInputDispatchMode(bool enabled, bool frozen) = 0;
+
+ /* Sets whether input event filtering is enabled.
+ * When enabled, incoming input events are sent to the policy's filterInputEvent
+ * method instead of being dispatched. The filter is expected to use
+ * injectInputEvent to inject the events it would like to have dispatched.
+ * It should include POLICY_FLAG_FILTERED in the policy flags during injection.
+ */
+ virtual void setInputFilterEnabled(bool enabled) = 0;
+
+ /* Transfers touch focus from one window to another window.
+ *
+ * Returns true on success. False if the window did not actually have touch focus.
+ */
+ virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 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).
+ */
+ virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
+ int32_t displayId) = 0;
+
+ /* Registers input channels to be used to monitor input events.
+ *
+ * Each monitor must target a specific display and will only receive input events sent to that
+ * display. If the monitor is a gesture monitor, it will only receive pointer events on the
+ * targeted display.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId,
+ bool gestureMonitor) = 0;
+
+ /* Unregister input channels that will no longer receive input events.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
+
+ /* Allows an input monitor steal the current pointer stream away from normal input windows.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual status_t pilferPointers(const sp<IBinder>& token) = 0;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
new file mode 100644
index 0000000..4214488
--- /dev/null
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H
+#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H
+
+#include "InputDispatcherConfiguration.h"
+
+#include <binder/IBinder.h>
+#include <input/Input.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class InputApplicationHandle;
+
+/*
+ * Input dispatcher policy interface.
+ *
+ * The input reader policy is used by the input reader to interact with the Window Manager
+ * and other system components.
+ *
+ * The actual implementation is partially supported by callbacks into the DVM
+ * via JNI. This interface is also mocked in the unit tests.
+ */
+class InputDispatcherPolicyInterface : public virtual RefBase {
+protected:
+ InputDispatcherPolicyInterface() {}
+ virtual ~InputDispatcherPolicyInterface() {}
+
+public:
+ /* Notifies the system that a configuration change has occurred. */
+ virtual void notifyConfigurationChanged(nsecs_t when) = 0;
+
+ /* Notifies the system that an application is not responding.
+ * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
+ virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) = 0;
+
+ /* Notifies the system that an input channel is unrecoverably broken. */
+ virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
+ virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;
+
+ /* Gets the input dispatcher configuration. */
+ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
+
+ /* Filters an input event.
+ * Return true to dispatch the event unmodified, false to consume the event.
+ * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED
+ * to injectInputEvent.
+ */
+ virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0;
+
+ /* Intercepts a key event immediately before queueing it.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing such as updating policy flags.
+ *
+ * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
+ * should be dispatched to applications.
+ */
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0;
+
+ /* Intercepts a touch, trackball or other motion event before queueing it.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing such as updating policy flags.
+ *
+ * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
+ * should be dispatched to applications.
+ */
+ virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
+ uint32_t& policyFlags) = 0;
+
+ /* Allows the policy a chance to intercept a key before dispatching. */
+ virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
+ const KeyEvent* keyEvent,
+ uint32_t policyFlags) = 0;
+
+ /* Allows the policy a chance to perform default processing for an unhandled key.
+ * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */
+ virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,
+ uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;
+
+ /* Notifies the policy about switch events.
+ */
+ virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
+ uint32_t policyFlags) = 0;
+
+ /* Poke user activity for an event dispatched to a window. */
+ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;
+
+ /* Checks whether a given application pid/uid has permission to inject input events
+ * into other applications.
+ *
+ * This method is special in that its implementation promises to be non-reentrant and
+ * is safe to call while holding other locks. (Most other methods make no such guarantees!)
+ */
+ virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
+ int32_t injectorUid) = 0;
+
+ /* Notifies the policy that a pointer down event has occurred outside the current focused
+ * window.
+ *
+ * The touchedToken passed as an argument is the window that received the input event.
+ */
+ virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherThread.h b/services/inputflinger/dispatcher/include/InputDispatcherThread.h
new file mode 100644
index 0000000..2604959
--- /dev/null
+++ b/services/inputflinger/dispatcher/include/InputDispatcherThread.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERTHREAD_H
+#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERTHREAD_H
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class InputDispatcherInterface;
+
+/* Enqueues and dispatches input events, endlessly. */
+class InputDispatcherThread : public Thread {
+public:
+ explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher);
+ ~InputDispatcherThread();
+
+private:
+ virtual bool threadLoop();
+
+ sp<InputDispatcherInterface> mDispatcher;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERTHREAD_H
diff --git a/services/inputflinger/reporter/Android.bp b/services/inputflinger/reporter/Android.bp
new file mode 100644
index 0000000..5956fb0
--- /dev/null
+++ b/services/inputflinger/reporter/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+ name: "libinputreporter_headers",
+ export_include_dirs: ["."],
+}
+
+cc_library_shared {
+ name: "libinputreporter",
+ defaults: ["inputflinger_defaults"],
+
+ srcs: [
+ "InputReporter.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libinputflinger_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libinputflinger_headers",
+ ],
+}
+
diff --git a/services/inputflinger/InputReporter.cpp b/services/inputflinger/reporter/InputReporter.cpp
similarity index 93%
rename from services/inputflinger/InputReporter.cpp
rename to services/inputflinger/reporter/InputReporter.cpp
index 8d3153c..b591d3f 100644
--- a/services/inputflinger/InputReporter.cpp
+++ b/services/inputflinger/reporter/InputReporter.cpp
@@ -27,15 +27,15 @@
};
void InputReporter::reportUnhandledKey(uint32_t sequenceNum) {
- // do nothing
+ // do nothing
}
void InputReporter::reportDroppedKey(uint32_t sequenceNum) {
- // do nothing
+ // do nothing
}
sp<InputReporterInterface> createInputReporter() {
- return new InputReporter();
+ return new InputReporter();
}
} // namespace android
diff --git a/services/inputflinger/include/InputReporterInterface.h b/services/inputflinger/reporter/InputReporterInterface.h
similarity index 97%
rename from services/inputflinger/include/InputReporterInterface.h
rename to services/inputflinger/reporter/InputReporterInterface.h
index 906d7f2..e5d3606 100644
--- a/services/inputflinger/include/InputReporterInterface.h
+++ b/services/inputflinger/reporter/InputReporterInterface.h
@@ -27,7 +27,7 @@
*/
class InputReporterInterface : public virtual RefBase {
protected:
- virtual ~InputReporterInterface() { }
+ virtual ~InputReporterInterface() {}
public:
// Report a key that was not handled by the system or apps.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 8474b1c..aa98ef7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -16,12 +16,14 @@
#include "../dispatcher/InputDispatcher.h"
+#include <InputDispatcherThread.h>
+
#include <binder/Binder.h>
#include <gtest/gtest.h>
#include <linux/input.h>
-namespace android {
+namespace android::inputdispatcher {
// An arbitrary time value.
static const nsecs_t ARBITRARY_TIME = 1234;
@@ -1082,4 +1084,4 @@
mFakePolicy->assertOnPointerDownEquals(nullptr);
}
-} // namespace android
+} // namespace android::inputdispatcher