diff options
author | 2019-09-26 20:01:25 +0000 | |
---|---|---|
committer | 2019-09-26 20:01:25 +0000 | |
commit | 0c1abd12f9b032e9150a0c12ee40d546cc314bec (patch) | |
tree | 6c0b0120b5edb87fbe7ab3f94350b4cf28c44fc6 | |
parent | 4f330b8eca915554e9f59c4f8f98ebddbcb81203 (diff) | |
parent | 394eed0255ffa1802375686d9fa78999b04e1753 (diff) |
Merge changes from topics "inputdispatcher-split-aosp", "inputreader-split-aosp"
* changes:
Create inputmappers and accumulators directories
Split InputReader into multiple files
Create inputreader directory
Divide InputDispatcher into several files.
Move InputDispatcher code into a folder.
83 files changed, 14521 insertions, 12945 deletions
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 8dd4d1df63..11578c393e 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -30,7 +30,6 @@ cc_library_shared { srcs: [ "InputClassifier.cpp", "InputClassifierConverter.cpp", - "InputDispatcher.cpp", "InputManager.cpp", ], @@ -50,6 +49,10 @@ cc_library_shared { "server_configurable_flags", ], + static_libs: [ + "libinputdispatcher", + ], + cflags: [ // TODO(b/23084678): Move inputflinger to its own process and mark it hidden //-fvisibility=hidden @@ -60,44 +63,16 @@ cc_library_shared { "include", ], + export_static_lib_headers: [ + "libinputdispatcher", + ], } cc_library_headers { name: "libinputflinger_headers", + header_libs: ["libinputreporter_headers"], export_include_dirs: ["include"], -} - -cc_library_shared { - name: "libinputreader", - defaults: ["inputflinger_defaults"], - - srcs: [ - "EventHub.cpp", - "InputReader.cpp", - "InputReaderFactory.cpp", - "TouchVideoDevice.cpp", - ], - - shared_libs: [ - "libbase", - "libinputflinger_base", - "libcrypto", - "libcutils", - "libinput", - "liblog", - "libui", - "libutils", - "libhardware_legacy", - "libstatslog", - ], - - header_libs: [ - "libinputflinger_headers", - ], - - export_header_lib_headers: [ - "libinputflinger_headers", - ], + export_header_lib_headers: ["libinputreporter_headers"], } cc_library_shared { @@ -125,28 +100,6 @@ cc_library_shared { ], } -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/InputDispatcher.h b/services/inputflinger/InputDispatcher.h deleted file mode 100644 index 753b748884..0000000000 --- a/services/inputflinger/InputDispatcher.h +++ /dev/null @@ -1,1305 +0,0 @@ -/* - * Copyright (C) 2010 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_DISPATCHER_H -#define _UI_INPUT_DISPATCHER_H - -#include <condition_variable> -#include <input/Input.h> -#include <input/InputApplication.h> -#include <input/InputTransport.h> -#include <input/InputWindow.h> -#include <input/ISetInputWindowsListener.h> -#include <optional> -#include <ui/Region.h> -#include <utils/threads.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/Looper.h> -#include <utils/BitSet.h> -#include <cutils/atomic.h> -#include <unordered_map> - -#include <stddef.h> -#include <unistd.h> -#include <limits.h> -#include <unordered_map> - -#include "InputListener.h" -#include "InputReporterInterface.h" - -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; - -}; - -/* Dispatches events to input targets. Some functions of the input dispatcher, such as - * identifying input targets, are controlled by a separate policy object. - * - * IMPORTANT INVARIANT: - * Because the policy can potentially block or cause re-entrance into the input dispatcher, - * the input dispatcher never calls into the policy while holding its internal locks. - * The implementation is also carefully designed to recover from scenarios such as an - * input channel becoming unregistered while identifying input targets or processing timeouts. - * - * Methods marked 'Locked' must be called with the lock acquired. - * - * Methods marked 'LockedInterruptible' must be called with the lock acquired but - * may during the course of their execution release the lock, call into the policy, and - * then reacquire the lock. The caller is responsible for recovering gracefully. - * - * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. - */ -class InputDispatcher : public InputDispatcherInterface { -protected: - virtual ~InputDispatcher(); - -public: - explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); - - virtual void dump(std::string& dump) override; - virtual void monitor() override; - - virtual void dispatchOnce() override; - - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; - virtual void notifyKey(const NotifyKeyArgs* args) override; - virtual void notifyMotion(const NotifyMotionArgs* args) override; - virtual void notifySwitch(const NotifySwitchArgs* args) override; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) override; - - virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles, - int32_t displayId, - const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override; - virtual void setFocusedApplication(int32_t displayId, - const sp<InputApplicationHandle>& inputApplicationHandle) override; - virtual void setFocusedDisplay(int32_t displayId) override; - virtual void setInputDispatchMode(bool enabled, bool frozen) override; - virtual void setInputFilterEnabled(bool enabled) override; - - virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) - override; - - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - int32_t displayId) override; - virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, - int32_t displayId, bool isGestureMonitor) override; - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override; - virtual status_t pilferPointers(const sp<IBinder>& token) override; - -private: - template <typename T> - struct Link { - T* next; - T* prev; - - protected: - inline Link() : next(nullptr), prev(nullptr) { } - }; - - 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 : Link<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; - 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, - 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 : Link<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 void (InputDispatcher::*Command)(CommandEntry* commandEntry); - - class Connection; - struct CommandEntry : Link<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; - }; - - // Generic queue implementation. - template <typename T> - struct Queue { - T* head; - T* tail; - uint32_t entryCount; - - inline Queue() : head(nullptr), tail(nullptr), entryCount(0) { - } - - inline bool isEmpty() const { - return !head; - } - - inline void enqueueAtTail(T* entry) { - entryCount++; - entry->prev = tail; - if (tail) { - tail->next = entry; - } else { - head = entry; - } - entry->next = nullptr; - tail = entry; - } - - inline void enqueueAtHead(T* entry) { - entryCount++; - entry->next = head; - if (head) { - head->prev = entry; - } else { - tail = entry; - } - entry->prev = nullptr; - head = entry; - } - - inline void dequeue(T* entry) { - entryCount--; - if (entry->prev) { - entry->prev->next = entry->next; - } else { - head = entry->next; - } - if (entry->next) { - entry->next->prev = entry->prev; - } else { - tail = entry->prev; - } - } - - inline T* dequeueAtHead() { - entryCount--; - T* entry = head; - head = entry->next; - if (head) { - head->prev = nullptr; - } else { - tail = nullptr; - } - return entry; - } - - uint32_t count() const { - return entryCount; - } - }; - - /* 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; - 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. - Queue<DispatchEntry> outboundQueue; - - // Queue of events that have been published to the connection but that have not - // yet received a "finished" response from the application. - Queue<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; - - DispatchEntry* findWaitQueueEntry(uint32_t seq); - }; - - struct Monitor { - sp<InputChannel> inputChannel; // never null - - explicit Monitor(const sp<InputChannel>& inputChannel); - }; - - enum DropReason { - DROP_REASON_NOT_DROPPED = 0, - DROP_REASON_POLICY = 1, - DROP_REASON_APP_SWITCH = 2, - DROP_REASON_DISABLED = 3, - DROP_REASON_BLOCKED = 4, - DROP_REASON_STALE = 5, - }; - - sp<InputDispatcherPolicyInterface> mPolicy; - InputDispatcherConfiguration mConfig; - - std::mutex mLock; - - std::condition_variable mDispatcherIsAlive; - - sp<Looper> mLooper; - - EventEntry* mPendingEvent GUARDED_BY(mLock); - Queue<EventEntry> mInboundQueue GUARDED_BY(mLock); - Queue<EventEntry> mRecentQueue GUARDED_BY(mLock); - Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock); - - DropReason mLastDropReason GUARDED_BY(mLock); - - void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) REQUIRES(mLock); - - // Enqueues an inbound event. Returns true if mLooper->wake() should be called. - bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock); - - // Cleans up input state when dropping an inbound event. - void dropInboundEventLocked(EventEntry* entry, DropReason dropReason) REQUIRES(mLock); - - // Adds an event to a queue of recent events for debugging purposes. - void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock); - - // App switch latency optimization. - bool mAppSwitchSawKeyDown GUARDED_BY(mLock); - nsecs_t mAppSwitchDueTime GUARDED_BY(mLock); - - bool isAppSwitchKeyEvent(KeyEntry* keyEntry); - bool isAppSwitchPendingLocked() REQUIRES(mLock); - void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock); - - // Stale event latency optimization. - static bool isStaleEvent(nsecs_t currentTime, EventEntry* entry); - - // Blocked event latency optimization. Drops old events when the user intends - // to transfer focus to a new application. - EventEntry* mNextUnblockedEvent GUARDED_BY(mLock); - - sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, - bool addOutsideTargets = false, bool addPortalWindows = false) REQUIRES(mLock); - - // All registered connections mapped by channel file descriptor. - KeyedVector<int, sp<Connection> > mConnectionsByFd GUARDED_BY(mLock); - - struct IBinderHash { - std::size_t operator()(const sp<IBinder>& b) const { - return std::hash<IBinder *>{}(b.get()); - } - }; - std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken - GUARDED_BY(mLock); - - // Finds the display ID of the gesture monitor identified by the provided token. - std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token) - REQUIRES(mLock); - - ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); - - // Input channels that will receive a copy of all input events sent to the provided display. - std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay - GUARDED_BY(mLock); - - // Input channels that will receive pointer events that start within the corresponding display. - // These are a bit special when compared to global monitors since they'll cause gesture streams - // to continue even when there isn't a touched window,and have the ability to steal the rest of - // the pointer stream in order to claim it for a system gesture. - std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay - GUARDED_BY(mLock); - - - // Event injection and synchronization. - std::condition_variable mInjectionResultAvailable; - bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); - void setInjectionResult(EventEntry* entry, int32_t injectionResult); - - std::condition_variable mInjectionSyncFinished; - void incrementPendingForegroundDispatches(EventEntry* entry); - void decrementPendingForegroundDispatches(EventEntry* entry); - - // Key repeat tracking. - struct KeyRepeatState { - KeyEntry* lastKeyEntry; // or null if no repeat - nsecs_t nextRepeatTime; - } mKeyRepeatState GUARDED_BY(mLock); - - void resetKeyRepeatLocked() REQUIRES(mLock); - KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock); - - // Key replacement tracking - struct KeyReplacement { - int32_t keyCode; - int32_t deviceId; - bool operator==(const KeyReplacement& rhs) const { - return keyCode == rhs.keyCode && deviceId == rhs.deviceId; - } - bool operator<(const KeyReplacement& rhs) const { - return keyCode != rhs.keyCode ? keyCode < rhs.keyCode : deviceId < rhs.deviceId; - } - }; - // Maps the key code replaced, device id tuple to the key code it was replaced with - KeyedVector<KeyReplacement, int32_t> mReplacedKeys GUARDED_BY(mLock); - // Process certain Meta + Key combinations - void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action, - int32_t& keyCode, int32_t& metaState); - - // Deferred command processing. - bool haveCommandsLocked() const REQUIRES(mLock); - bool runCommandsLockedInterruptible() REQUIRES(mLock); - CommandEntry* postCommandLocked(Command command) REQUIRES(mLock); - - // Input filter processing. - bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock); - bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) REQUIRES(mLock); - - // Inbound event processing. - void drainInboundQueueLocked() REQUIRES(mLock); - void releasePendingEventLocked() REQUIRES(mLock); - void releaseInboundEventLocked(EventEntry* entry) REQUIRES(mLock); - - // Dispatch state. - bool mDispatchEnabled GUARDED_BY(mLock); - bool mDispatchFrozen GUARDED_BY(mLock); - bool mInputFilterEnabled GUARDED_BY(mLock); - - std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay - GUARDED_BY(mLock); - // Get window handles by display, return an empty vector if not found. - std::vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const - REQUIRES(mLock); - sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const - REQUIRES(mLock); - sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock); - bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); - - // Focus tracking for keys, trackball, etc. - 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); - - // Focused applications. - std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay - GUARDED_BY(mLock); - - // Top focused display. - int32_t mFocusedDisplayId GUARDED_BY(mLock); - - // Dispatcher state at time of last ANR. - std::string mLastANRState GUARDED_BY(mLock); - - // Dispatch inbound events. - bool dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry) REQUIRES(mLock); - bool dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry) REQUIRES(mLock); - bool dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock); - bool dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock); - void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, - const std::vector<InputTarget>& inputTargets) REQUIRES(mLock); - - void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry); - void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry); - - // Keeping track of ANR timeouts. - enum InputTargetWaitCause { - INPUT_TARGET_WAIT_CAUSE_NONE, - INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, - INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, - }; - - InputTargetWaitCause mInputTargetWaitCause GUARDED_BY(mLock); - nsecs_t mInputTargetWaitStartTime GUARDED_BY(mLock); - nsecs_t mInputTargetWaitTimeoutTime GUARDED_BY(mLock); - bool mInputTargetWaitTimeoutExpired GUARDED_BY(mLock); - sp<IBinder> mInputTargetWaitApplicationToken GUARDED_BY(mLock); - - // Contains the last window which received a hover event. - sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock); - - // Finding targets for input events. - int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t* nextWakeupTime, const char* reason) REQUIRES(mLock); - - void removeWindowByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock); - - void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp<InputChannel>& inputChannel) REQUIRES(mLock); - nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock); - void resetANRTimeoutsLocked() REQUIRES(mLock); - - int32_t getTargetDisplayId(const EventEntry* entry); - int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, - std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) REQUIRES(mLock); - int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, - std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions) REQUIRES(mLock); - std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked(int32_t displayId, - const std::vector<sp<InputWindowHandle>>& portalWindows) REQUIRES(mLock); - void addGestureMonitors(const std::vector<Monitor>& monitors, - std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0, float yOffset = 0); - - void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) - REQUIRES(mLock); - void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset, - std::vector<InputTarget>& inputTargets) REQUIRES(mLock); - void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, - int32_t displayId, float xOffset = 0, float yOffset = 0) REQUIRES(mLock); - - void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock); - bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, - const InjectionState* injectionState); - bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, - int32_t x, int32_t y) const REQUIRES(mLock); - bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); - std::string getApplicationWindowLabel(const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle); - - std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, - const char* targetType) REQUIRES(mLock); - - // Manage the dispatch cycle for a single connection. - // These methods are deliberately not Interruptible because doing all of the work - // with the mutex held makes it easier to ensure that connection invariants are maintained. - // If needed, the methods post commands to run later once the critical bits are done. - void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock); - void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock); - void enqueueDispatchEntryLocked(const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) - REQUIRES(mLock); - void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) - REQUIRES(mLock); - void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - uint32_t seq, bool handled) REQUIRES(mLock); - void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - bool notify) REQUIRES(mLock); - void drainDispatchQueue(Queue<DispatchEntry>* queue); - void releaseDispatchEntry(DispatchEntry* dispatchEntry); - static int handleReceiveCallback(int fd, int events, void* data); - // The action sent should only be of type AMOTION_EVENT_* - void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, - const sp<IBinder>& newToken) REQUIRES(mLock); - - void synthesizeCancelationEventsForAllConnectionsLocked( - const CancelationOptions& options) REQUIRES(mLock); - void synthesizeCancelationEventsForMonitorsLocked( - const CancelationOptions& options) REQUIRES(mLock); - void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options, - std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock); - void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, - const CancelationOptions& options) REQUIRES(mLock); - void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, - const CancelationOptions& options) REQUIRES(mLock); - - // Splitting motion events across windows. - MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); - - // Reset and drop everything the dispatcher is doing. - void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock); - - // Dump state. - void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock); - void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors); - void logDispatchStateLocked() REQUIRES(mLock); - - // Registration. - void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); - void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel, - std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) - REQUIRES(mLock); - status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify) - REQUIRES(mLock); - - // Interesting events that we might like to log or tell the framework about. - void onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) - REQUIRES(mLock); - void onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp<Connection>& connection) REQUIRES(mLock); - void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus, - const sp<InputWindowHandle>& newFocus) REQUIRES(mLock); - void onANRLocked( - nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) REQUIRES(mLock); - - // Outbound policy interactions. - void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) - REQUIRES(mLock); - void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void doNotifyANRLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry) - REQUIRES(mLock); - void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) REQUIRES(mLock); - bool afterMotionEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) REQUIRES(mLock); - void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); - void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); - void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) - REQUIRES(mLock); - - // Statistics gathering. - void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); - void traceInboundQueueLengthLocked() REQUIRES(mLock); - void traceOutboundQueueLength(const sp<Connection>& connection); - void traceWaitQueueLength(const sp<Connection>& connection); - - 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 - -#endif // _UI_INPUT_DISPATCHER_H diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 3996cca646..359325faed 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 @@ namespace android { 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 e568df54df..f3da324ba4 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -21,15 +21,14 @@ * Native input manager. */ -#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 +38,7 @@ namespace android { class InputChannel; +class InputDispatcherThread; /* * The input manager is the core of the system event processing. diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp deleted file mode 100644 index a45b8a56ce..0000000000 --- a/services/inputflinger/InputReader.cpp +++ /dev/null @@ -1,7534 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#define LOG_TAG "InputReader" - -//#define LOG_NDEBUG 0 - -// Log debug messages for each raw event received from the EventHub. -#define DEBUG_RAW_EVENTS 0 - -// Log debug messages about touch screen filtering hacks. -#define DEBUG_HACKS 0 - -// Log debug messages about virtual key processing. -#define DEBUG_VIRTUAL_KEYS 0 - -// Log debug messages about pointers. -#define DEBUG_POINTERS 0 - -// Log debug messages about pointer assignment calculations. -#define DEBUG_POINTER_ASSIGNMENT 0 - -// Log debug messages about gesture detection. -#define DEBUG_GESTURES 0 - -// Log debug messages about the vibrator. -#define DEBUG_VIBRATOR 0 - -// Log debug messages about fusing stylus data. -#define DEBUG_STYLUS_FUSION 0 - -#include "InputReader.h" - -#include <errno.h> -#include <inttypes.h> -#include <limits.h> -#include <math.h> -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> - -#include <log/log.h> - -#include <android-base/stringprintf.h> -#include <input/Keyboard.h> -#include <input/VirtualKeyMap.h> -#include <statslog.h> - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " -#define INDENT5 " " - -using android::base::StringPrintf; - -namespace android { - -// --- Constants --- - -// Maximum number of slots supported when using the slot-based Multitouch Protocol B. -static constexpr size_t MAX_SLOTS = 32; - -// Maximum amount of latency to add to touch events while waiting for data from an -// external stylus. -static constexpr nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); - -// Maximum amount of time to wait on touch data before pushing out new pressure data. -static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); - -// Artificial latency on synthetic events created from stylus data without corresponding touch -// data. -static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); - -// How often to report input event statistics -static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60); - -// --- Static Functions --- - -template<typename T> -inline static T abs(const T& value) { - return value < 0 ? - value : value; -} - -template<typename T> -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -template<typename T> -inline static void swap(T& a, T& b) { - T temp = a; - a = b; - b = temp; -} - -inline static float avg(float x, float y) { - return (x + y) / 2; -} - -inline static float distance(float x1, float y1, float x2, float y2) { - return hypotf(x1 - x2, y1 - y2); -} - -inline static int32_t signExtendNybble(int32_t value) { - return value >= 8 ? value - 16 : value; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, - const int32_t map[][4], size_t mapSize) { - if (orientation != DISPLAY_ORIENTATION_0) { - for (size_t i = 0; i < mapSize; i++) { - if (value == map[i][0]) { - return map[i][orientation]; - } - } - } - return value; -} - -static const int32_t keyCodeRotationMap[][4] = { - // key codes enumerated counter-clockwise with the original (unrotated) key first - // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation - { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, - { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, - { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, - { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, - { AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT, - AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT }, - { AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP, - AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN }, - { AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT, - AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT }, - { AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN, - AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP }, -}; -static const size_t keyCodeRotationMapSize = - sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); - -static int32_t rotateStemKey(int32_t value, int32_t orientation, - const int32_t map[][2], size_t mapSize) { - if (orientation == DISPLAY_ORIENTATION_180) { - for (size_t i = 0; i < mapSize; i++) { - if (value == map[i][0]) { - return map[i][1]; - } - } - } - return value; -} - -// The mapping can be defined using input device configuration properties keyboard.rotated.stem_X -static int32_t stemKeyRotationMap[][2] = { - // key codes enumerated with the original (unrotated) key first - // no rotation, 180 degree rotation - { AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY }, - { AKEYCODE_STEM_1, AKEYCODE_STEM_1 }, - { AKEYCODE_STEM_2, AKEYCODE_STEM_2 }, - { AKEYCODE_STEM_3, AKEYCODE_STEM_3 }, -}; -static const size_t stemKeyRotationMapSize = - sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]); - -static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { - keyCode = rotateStemKey(keyCode, orientation, - stemKeyRotationMap, stemKeyRotationMapSize); - return rotateValueUsingRotationMap(keyCode, orientation, - keyCodeRotationMap, keyCodeRotationMapSize); -} - -static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { - float temp; - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = *deltaX; - *deltaX = *deltaY; - *deltaY = -temp; - break; - - case DISPLAY_ORIENTATION_180: - *deltaX = -*deltaX; - *deltaY = -*deltaY; - break; - - case DISPLAY_ORIENTATION_270: - temp = *deltaX; - *deltaX = -*deltaY; - *deltaY = temp; - break; - } -} - -static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { - return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; -} - -// Returns true if the pointer should be reported as being down given the specified -// button states. This determines whether the event is reported as a touch event. -static bool isPointerDown(int32_t buttonState) { - return buttonState & - (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY - | AMOTION_EVENT_BUTTON_TERTIARY); -} - -static float calculateCommonVector(float a, float b) { - if (a > 0 && b > 0) { - return a < b ? a : b; - } else if (a < 0 && b < 0) { - return a > b ? a : b; - } else { - return 0; - } -} - -static void synthesizeButtonKey(InputReaderContext* context, int32_t action, - nsecs_t when, int32_t deviceId, uint32_t source, int32_t displayId, - uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, - int32_t buttonState, int32_t keyCode) { - if ( - (action == AKEY_EVENT_ACTION_DOWN - && !(lastButtonState & buttonState) - && (currentButtonState & buttonState)) - || (action == AKEY_EVENT_ACTION_UP - && (lastButtonState & buttonState) - && !(currentButtonState & buttonState))) { - NotifyKeyArgs args(context->getNextSequenceNum(), when, deviceId, source, displayId, - policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when); - context->getListener()->notifyKey(&args); - } -} - -static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, - nsecs_t when, int32_t deviceId, uint32_t source, int32_t displayId, - uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { - synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags, - lastButtonState, currentButtonState, - AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); - synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags, - lastButtonState, currentButtonState, - AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD); -} - - -// --- InputReader --- - -InputReader::InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener) : - mContext(this), mEventHub(eventHub), mPolicy(policy), - mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1), - mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), - mConfigurationChangesToRefresh(0) { - mQueuedListener = new QueuedInputListener(listener); - - { // acquire lock - AutoMutex _l(mLock); - - refreshConfigurationLocked(0); - updateGlobalMetaStateLocked(); - } // release lock -} - -InputReader::~InputReader() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } -} - -void InputReader::loopOnce() { - int32_t oldGeneration; - int32_t timeoutMillis; - bool inputDevicesChanged = false; - std::vector<InputDeviceInfo> inputDevices; - { // acquire lock - AutoMutex _l(mLock); - - oldGeneration = mGeneration; - timeoutMillis = -1; - - uint32_t changes = mConfigurationChangesToRefresh; - if (changes) { - mConfigurationChangesToRefresh = 0; - timeoutMillis = 0; - refreshConfigurationLocked(changes); - } else if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); - } - } // release lock - - size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); - - { // acquire lock - AutoMutex _l(mLock); - mReaderIsAliveCondition.broadcast(); - - if (count) { - processEventsLocked(mEventBuffer, count); - } - - if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (now >= mNextTimeout) { -#if DEBUG_RAW_EVENTS - ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); -#endif - mNextTimeout = LLONG_MAX; - timeoutExpiredLocked(now); - } - } - - if (oldGeneration != mGeneration) { - inputDevicesChanged = true; - getInputDevicesLocked(inputDevices); - } - } // release lock - - // Send out a message that the describes the changed input devices. - if (inputDevicesChanged) { - mPolicy->notifyInputDevicesChanged(inputDevices); - } - - // Flush queued events out to the listener. - // This must happen outside of the lock because the listener could potentially call - // back into the InputReader's methods, such as getScanCodeState, or become blocked - // on another thread similarly waiting to acquire the InputReader lock thereby - // resulting in a deadlock. This situation is actually quite plausible because the - // listener is actually the input dispatcher, which calls into the window manager, - // which occasionally calls into the input reader. - mQueuedListener->flush(); -} - -void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { - for (const RawEvent* rawEvent = rawEvents; count;) { - int32_t type = rawEvent->type; - size_t batchSize = 1; - if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { - int32_t deviceId = rawEvent->deviceId; - while (batchSize < count) { - if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT - || rawEvent[batchSize].deviceId != deviceId) { - break; - } - batchSize += 1; - } -#if DEBUG_RAW_EVENTS - ALOGD("BatchSize: %zu Count: %zu", batchSize, count); -#endif - processEventsForDeviceLocked(deviceId, rawEvent, batchSize); - } else { - switch (rawEvent->type) { - case EventHubInterface::DEVICE_ADDED: - addDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::DEVICE_REMOVED: - removeDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChangedLocked(rawEvent->when); - break; - default: - ALOG_ASSERT(false); // can't happen - break; - } - } - count -= batchSize; - rawEvent += batchSize; - } -} - -void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); - return; - } - - InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); - uint32_t classes = mEventHub->getDeviceClasses(deviceId); - int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); - - InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); - device->configure(when, &mConfig, 0); - device->reset(when); - - if (device->isIgnored()) { - ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, - identifier.name.c_str()); - } else { - ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, - identifier.name.c_str(), device->getSources()); - } - - mDevices.add(deviceId, device); - bumpGenerationLocked(); - - if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { - notifyExternalStylusPresenceChanged(); - } -} - -void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { - InputDevice* device = nullptr; - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); - return; - } - - device = mDevices.valueAt(deviceIndex); - mDevices.removeItemsAt(deviceIndex, 1); - bumpGenerationLocked(); - - if (device->isIgnored()) { - ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", - device->getId(), device->getName().c_str()); - } else { - ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", - device->getId(), device->getName().c_str(), device->getSources()); - } - - if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { - notifyExternalStylusPresenceChanged(); - } - - device->reset(when); - delete device; -} - -InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, uint32_t classes) { - InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), - controllerNumber, identifier, classes); - - // External devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { - device->setExternal(true); - } - - // Devices with mics. - if (classes & INPUT_DEVICE_CLASS_MIC) { - device->setMic(true); - } - - // Switch-like devices. - if (classes & INPUT_DEVICE_CLASS_SWITCH) { - device->addMapper(new SwitchInputMapper(device)); - } - - // Scroll wheel-like devices. - if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { - device->addMapper(new RotaryEncoderInputMapper(device)); - } - - // Vibrator-like devices. - if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { - device->addMapper(new VibratorInputMapper(device)); - } - - // Keyboard-like devices. - uint32_t keyboardSource = 0; - int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; - if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { - keyboardSource |= AINPUT_SOURCE_KEYBOARD; - } - if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { - keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; - } - if (classes & INPUT_DEVICE_CLASS_DPAD) { - keyboardSource |= AINPUT_SOURCE_DPAD; - } - if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { - keyboardSource |= AINPUT_SOURCE_GAMEPAD; - } - - if (keyboardSource != 0) { - device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); - } - - // Cursor-like devices. - if (classes & INPUT_DEVICE_CLASS_CURSOR) { - device->addMapper(new CursorInputMapper(device)); - } - - // Touchscreens and touchpad devices. - if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { - device->addMapper(new MultiTouchInputMapper(device)); - } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { - device->addMapper(new SingleTouchInputMapper(device)); - } - - // Joystick-like devices. - if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { - device->addMapper(new JoystickInputMapper(device)); - } - - // External stylus-like devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { - device->addMapper(new ExternalStylusInputMapper(device)); - } - - return device; -} - -void InputReader::processEventsForDeviceLocked(int32_t deviceId, - const RawEvent* rawEvents, size_t count) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Discarding event for unknown deviceId %d.", deviceId); - return; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - //ALOGD("Discarding event for ignored deviceId %d.", deviceId); - return; - } - - device->process(rawEvents, count); -} - -void InputReader::timeoutExpiredLocked(nsecs_t when) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - device->timeoutExpired(when); - } - } -} - -void InputReader::handleConfigurationChangedLocked(nsecs_t when) { - // Reset global meta state because it depends on the list of all configured devices. - updateGlobalMetaStateLocked(); - - // Enqueue configuration changed. - NotifyConfigurationChangedArgs args(mContext.getNextSequenceNum(), when); - mQueuedListener->notifyConfigurationChanged(&args); -} - -void InputReader::refreshConfigurationLocked(uint32_t changes) { - mPolicy->getReaderConfiguration(&mConfig); - mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); - - if (changes) { - ALOGI("Reconfiguring input devices. changes=0x%08x", changes); - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { - mEventHub->requestReopenDevices(); - } else { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->configure(now, &mConfig, changes); - } - } - } -} - -void InputReader::updateGlobalMetaStateLocked() { - mGlobalMetaState = 0; - - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - mGlobalMetaState |= device->getMetaState(); - } -} - -int32_t InputReader::getGlobalMetaStateLocked() { - return mGlobalMetaState; -} - -void InputReader::notifyExternalStylusPresenceChanged() { - refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); -} - -void InputReader::getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { - InputDeviceInfo info; - device->getDeviceInfo(&info); - outDevices.push_back(info); - } - } -} - -void InputReader::dispatchExternalStylusState(const StylusState& state) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->updateExternalStylusState(state); - } -} - -void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { - mDisableVirtualKeysTimeout = time; -} - -bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - if (now < mDisableVirtualKeysTimeout) { - ALOGI("Dropping virtual key from device %s because virtual keys are " - "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", - device->getName().c_str(), - (mDisableVirtualKeysTimeout - now) * 0.000001, - keyCode, scanCode); - return true; - } else { - return false; - } -} - -void InputReader::fadePointerLocked() { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->fadePointer(); - } -} - -void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { - if (when < mNextTimeout) { - mNextTimeout = when; - mEventHub->wake(); - } -} - -int32_t InputReader::bumpGenerationLocked() { - return ++mGeneration; -} - -void InputReader::getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) { - AutoMutex _l(mLock); - getInputDevicesLocked(outInputDevices); -} - -void InputReader::getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices) { - outInputDevices.clear(); - - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - InputDeviceInfo info; - device->getDeviceInfo(&info); - outInputDevices.push_back(info); - } - } -} - -int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); -} - -int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); -} - -int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); -} - -int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device->*getStateFunc)(sourceMask, code); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. - int32_t currentResult = (device->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - } - return result; -} - -void InputReader::toggleCapsLockState(int32_t deviceId) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId); - return; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - return; - } - - device->updateMetaState(AKEYCODE_CAPS_LOCK); -} - -bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - AutoMutex _l(mLock); - - memset(outFlags, 0, numCodes); - return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); -} - -bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result |= device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } - return result; -} - -void InputReader::requestRefreshConfiguration(uint32_t changes) { - AutoMutex _l(mLock); - - if (changes) { - bool needWake = !mConfigurationChangesToRefresh; - mConfigurationChangesToRefresh |= changes; - - if (needWake) { - mEventHub->wake(); - } - } -} - -void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->cancelVibrate(token); - } -} - -bool InputReader::isInputDeviceEnabled(int32_t deviceId) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - return device->isEnabled(); - } - ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); - return false; -} - -bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); - return false; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplay(); - // No associated display. By default, can dispatch to all displays. - if (!associatedDisplayId) { - return true; - } - - if (*associatedDisplayId == ADISPLAY_ID_NONE) { - ALOGW("Device has associated, but no associated display id."); - return true; - } - - return *associatedDisplayId == displayId; -} - -void InputReader::dump(std::string& dump) { - AutoMutex _l(mLock); - - mEventHub->dump(dump); - dump += "\n"; - - dump += "Input Reader State:\n"; - - for (size_t i = 0; i < mDevices.size(); i++) { - mDevices.valueAt(i)->dump(dump); - } - - dump += INDENT "Configuration:\n"; - dump += INDENT2 "ExcludedDeviceNames: ["; - for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { - if (i != 0) { - dump += ", "; - } - dump += mConfig.excludedDeviceNames[i]; - } - dump += "]\n"; - dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", - mConfig.virtualKeyQuietTime * 0.000001f); - - dump += StringPrintf(INDENT2 "PointerVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", - mConfig.pointerVelocityControlParameters.scale, - mConfig.pointerVelocityControlParameters.lowThreshold, - mConfig.pointerVelocityControlParameters.highThreshold, - mConfig.pointerVelocityControlParameters.acceleration); - - dump += StringPrintf(INDENT2 "WheelVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", - mConfig.wheelVelocityControlParameters.scale, - mConfig.wheelVelocityControlParameters.lowThreshold, - mConfig.wheelVelocityControlParameters.highThreshold, - mConfig.wheelVelocityControlParameters.acceleration); - - dump += StringPrintf(INDENT2 "PointerGesture:\n"); - dump += StringPrintf(INDENT3 "Enabled: %s\n", - toString(mConfig.pointerGesturesEnabled)); - dump += StringPrintf(INDENT3 "QuietInterval: %0.1fms\n", - mConfig.pointerGestureQuietInterval * 0.000001f); - dump += StringPrintf(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", - mConfig.pointerGestureDragMinSwitchSpeed); - dump += StringPrintf(INDENT3 "TapInterval: %0.1fms\n", - mConfig.pointerGestureTapInterval * 0.000001f); - dump += StringPrintf(INDENT3 "TapDragInterval: %0.1fms\n", - mConfig.pointerGestureTapDragInterval * 0.000001f); - dump += StringPrintf(INDENT3 "TapSlop: %0.1fpx\n", - mConfig.pointerGestureTapSlop); - dump += StringPrintf(INDENT3 "MultitouchSettleInterval: %0.1fms\n", - mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); - dump += StringPrintf(INDENT3 "MultitouchMinDistance: %0.1fpx\n", - mConfig.pointerGestureMultitouchMinDistance); - dump += StringPrintf(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", - mConfig.pointerGestureSwipeTransitionAngleCosine); - dump += StringPrintf(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", - mConfig.pointerGestureSwipeMaxWidthRatio); - dump += StringPrintf(INDENT3 "MovementSpeedRatio: %0.1f\n", - mConfig.pointerGestureMovementSpeedRatio); - dump += StringPrintf(INDENT3 "ZoomSpeedRatio: %0.1f\n", - mConfig.pointerGestureZoomSpeedRatio); - - dump += INDENT3 "Viewports:\n"; - mConfig.dump(dump); -} - -void InputReader::monitor() { - // Acquire and release the lock to ensure that the reader has not deadlocked. - mLock.lock(); - mEventHub->wake(); - mReaderIsAliveCondition.wait(mLock); - mLock.unlock(); - - // Check the EventHub - mEventHub->monitor(); -} - - -// --- InputReader::ContextImpl --- - -InputReader::ContextImpl::ContextImpl(InputReader* reader) : - mReader(reader) { -} - -void InputReader::ContextImpl::updateGlobalMetaState() { - // lock is already held by the input loop - mReader->updateGlobalMetaStateLocked(); -} - -int32_t InputReader::ContextImpl::getGlobalMetaState() { - // lock is already held by the input loop - return mReader->getGlobalMetaStateLocked(); -} - -void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { - // lock is already held by the input loop - mReader->disableVirtualKeysUntilLocked(time); -} - -bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - // lock is already held by the input loop - return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); -} - -void InputReader::ContextImpl::fadePointer() { - // lock is already held by the input loop - mReader->fadePointerLocked(); -} - -void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { - // lock is already held by the input loop - mReader->requestTimeoutAtTimeLocked(when); -} - -int32_t InputReader::ContextImpl::bumpGeneration() { - // lock is already held by the input loop - return mReader->bumpGenerationLocked(); -} - -void InputReader::ContextImpl::getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) { - // lock is already held by whatever called refreshConfigurationLocked - mReader->getExternalStylusDevicesLocked(outDevices); -} - -void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { - mReader->dispatchExternalStylusState(state); -} - -InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { - return mReader->mPolicy.get(); -} - -InputListenerInterface* InputReader::ContextImpl::getListener() { - return mReader->mQueuedListener.get(); -} - -EventHubInterface* InputReader::ContextImpl::getEventHub() { - return mReader->mEventHub.get(); -} - -uint32_t InputReader::ContextImpl::getNextSequenceNum() { - return (mReader->mNextSequenceNum)++; -} - -// --- InputDevice --- - -InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) : - mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber), - mIdentifier(identifier), mClasses(classes), - mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) { -} - -InputDevice::~InputDevice() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - delete mMappers[i]; - } - mMappers.clear(); -} - -bool InputDevice::isEnabled() { - return getEventHub()->isDeviceEnabled(mId); -} - -void InputDevice::setEnabled(bool enabled, nsecs_t when) { - if (isEnabled() == enabled) { - return; - } - - if (enabled) { - getEventHub()->enableDevice(mId); - reset(when); - } else { - reset(when); - getEventHub()->disableDevice(mId); - } - // Must change generation to flag this device as changed - bumpGeneration(); -} - -void InputDevice::dump(std::string& dump) { - InputDeviceInfo deviceInfo; - getDeviceInfo(&deviceInfo); - - dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(), - deviceInfo.getDisplayName().c_str()); - dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration); - dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); - dump += StringPrintf(INDENT2 "AssociatedDisplayPort: "); - if (mAssociatedDisplayPort) { - dump += StringPrintf("%" PRIu8 "\n", *mAssociatedDisplayPort); - } else { - dump += "<none>\n"; - } - dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic)); - dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); - dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); - - const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); - if (!ranges.empty()) { - dump += INDENT2 "Motion Ranges:\n"; - for (size_t i = 0; i < ranges.size(); i++) { - const InputDeviceInfo::MotionRange& range = ranges[i]; - const char* label = getAxisLabel(range.axis); - char name[32]; - if (label) { - strncpy(name, label, sizeof(name)); - name[sizeof(name) - 1] = '\0'; - } else { - snprintf(name, sizeof(name), "%d", range.axis); - } - dump += StringPrintf(INDENT3 "%s: source=0x%08x, " - "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", - name, range.source, range.min, range.max, range.flat, range.fuzz, - range.resolution); - } - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->dump(dump); - } -} - -void InputDevice::addMapper(InputMapper* mapper) { - mMappers.push_back(mapper); -} - -void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { - mSources = 0; - - if (!isIgnored()) { - if (!changes) { // first time only - mContext->getEventHub()->getConfiguration(mId, &mConfiguration); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - sp<KeyCharacterMap> keyboardLayout = - mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); - if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { - bumpGeneration(); - } - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); - if (mAlias != alias) { - mAlias = alias; - bumpGeneration(); - } - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { - ssize_t index = config->disabledDevices.indexOf(mId); - bool enabled = index < 0; - setEnabled(enabled, when); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - // In most situations, no port will be specified. - mAssociatedDisplayPort = std::nullopt; - // Find the display port that corresponds to the current input port. - const std::string& inputPort = mIdentifier.location; - if (!inputPort.empty()) { - const std::unordered_map<std::string, uint8_t>& ports = config->portAssociations; - const auto& displayPort = ports.find(inputPort); - if (displayPort != ports.end()) { - mAssociatedDisplayPort = std::make_optional(displayPort->second); - } - } - } - - for (InputMapper* mapper : mMappers) { - mapper->configure(when, config, changes); - mSources |= mapper->getSources(); - } - } -} - -void InputDevice::reset(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->reset(when); - } - - mContext->updateGlobalMetaState(); - - notifyReset(when); -} - -void InputDevice::process(const RawEvent* rawEvents, size_t count) { - // Process all of the events in order for each mapper. - // We cannot simply ask each mapper to process them in bulk because mappers may - // have side-effects that must be interleaved. For example, joystick movement events and - // gamepad button presses are handled by different mappers but they should be dispatched - // in the order received. - for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { -#if DEBUG_RAW_EVENTS - ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64, - rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, - rawEvent->when); -#endif - - if (mDropUntilNextSync) { - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - mDropUntilNextSync = false; -#if DEBUG_RAW_EVENTS - ALOGD("Recovered from input event buffer overrun."); -#endif - } else { -#if DEBUG_RAW_EVENTS - ALOGD("Dropped input event while waiting for next input sync."); -#endif - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { - ALOGI("Detected input event buffer overrun for device %s.", getName().c_str()); - mDropUntilNextSync = true; - reset(rawEvent->when); - } else { - for (InputMapper* mapper : mMappers) { - mapper->process(rawEvent); - } - } - --count; - } -} - -void InputDevice::timeoutExpired(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->timeoutExpired(when); - } -} - -void InputDevice::updateExternalStylusState(const StylusState& state) { - for (InputMapper* mapper : mMappers) { - mapper->updateExternalStylusState(state); - } -} - -void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { - outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, - mIsExternal, mHasMic); - for (InputMapper* mapper : mMappers) { - mapper->populateDeviceInfo(outDeviceInfo); - } -} - -int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState); -} - -int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getState(sourceMask, scanCode, & InputMapper::getScanCodeState); -} - -int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getState(sourceMask, switchCode, & InputMapper::getSwitchState); -} - -int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - for (InputMapper* mapper : mMappers) { - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. - int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - return result; -} - -bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - for (InputMapper* mapper : mMappers) { - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } - } - return result; -} - -void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { - for (InputMapper* mapper : mMappers) { - mapper->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputDevice::cancelVibrate(int32_t token) { - for (InputMapper* mapper : mMappers) { - mapper->cancelVibrate(token); - } -} - -void InputDevice::cancelTouch(nsecs_t when) { - for (InputMapper* mapper : mMappers) { - mapper->cancelTouch(when); - } -} - -int32_t InputDevice::getMetaState() { - int32_t result = 0; - for (InputMapper* mapper : mMappers) { - result |= mapper->getMetaState(); - } - return result; -} - -void InputDevice::updateMetaState(int32_t keyCode) { - for (InputMapper* mapper : mMappers) { - mapper->updateMetaState(keyCode); - } -} - -void InputDevice::fadePointer() { - for (InputMapper* mapper : mMappers) { - mapper->fadePointer(); - } -} - -void InputDevice::bumpGeneration() { - mGeneration = mContext->bumpGeneration(); -} - -void InputDevice::notifyReset(nsecs_t when) { - NotifyDeviceResetArgs args(mContext->getNextSequenceNum(), when, mId); - mContext->getListener()->notifyDeviceReset(&args); -} - -std::optional<int32_t> InputDevice::getAssociatedDisplay() { - for (InputMapper* mapper : mMappers) { - std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay(); - if (associatedDisplayId) { - return associatedDisplayId; - } - } - - return std::nullopt; -} - -// --- CursorButtonAccumulator --- - -CursorButtonAccumulator::CursorButtonAccumulator() { - clearButtons(); -} - -void CursorButtonAccumulator::reset(InputDevice* device) { - mBtnLeft = device->isKeyPressed(BTN_LEFT); - mBtnRight = device->isKeyPressed(BTN_RIGHT); - mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); - mBtnBack = device->isKeyPressed(BTN_BACK); - mBtnSide = device->isKeyPressed(BTN_SIDE); - mBtnForward = device->isKeyPressed(BTN_FORWARD); - mBtnExtra = device->isKeyPressed(BTN_EXTRA); - mBtnTask = device->isKeyPressed(BTN_TASK); -} - -void CursorButtonAccumulator::clearButtons() { - mBtnLeft = 0; - mBtnRight = 0; - mBtnMiddle = 0; - mBtnBack = 0; - mBtnSide = 0; - mBtnForward = 0; - mBtnExtra = 0; - mBtnTask = 0; -} - -void CursorButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_LEFT: - mBtnLeft = rawEvent->value; - break; - case BTN_RIGHT: - mBtnRight = rawEvent->value; - break; - case BTN_MIDDLE: - mBtnMiddle = rawEvent->value; - break; - case BTN_BACK: - mBtnBack = rawEvent->value; - break; - case BTN_SIDE: - mBtnSide = rawEvent->value; - break; - case BTN_FORWARD: - mBtnForward = rawEvent->value; - break; - case BTN_EXTRA: - mBtnExtra = rawEvent->value; - break; - case BTN_TASK: - mBtnTask = rawEvent->value; - break; - } - } -} - -uint32_t CursorButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnLeft) { - result |= AMOTION_EVENT_BUTTON_PRIMARY; - } - if (mBtnRight) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (mBtnMiddle) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; - } - if (mBtnBack || mBtnSide) { - result |= AMOTION_EVENT_BUTTON_BACK; - } - if (mBtnForward || mBtnExtra) { - result |= AMOTION_EVENT_BUTTON_FORWARD; - } - return result; -} - - -// --- CursorMotionAccumulator --- - -CursorMotionAccumulator::CursorMotionAccumulator() { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::clearRelativeAxes() { - mRelX = 0; - mRelY = 0; -} - -void CursorMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_X: - mRelX = rawEvent->value; - break; - case REL_Y: - mRelY = rawEvent->value; - break; - } - } -} - -void CursorMotionAccumulator::finishSync() { - clearRelativeAxes(); -} - - -// --- CursorScrollAccumulator --- - -CursorScrollAccumulator::CursorScrollAccumulator() : - mHaveRelWheel(false), mHaveRelHWheel(false) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::configure(InputDevice* device) { - mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); - mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); -} - -void CursorScrollAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::clearRelativeAxes() { - mRelWheel = 0; - mRelHWheel = 0; -} - -void CursorScrollAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_WHEEL: - mRelWheel = rawEvent->value; - break; - case REL_HWHEEL: - mRelHWheel = rawEvent->value; - break; - } - } -} - -void CursorScrollAccumulator::finishSync() { - clearRelativeAxes(); -} - - -// --- TouchButtonAccumulator --- - -TouchButtonAccumulator::TouchButtonAccumulator() : - mHaveBtnTouch(false), mHaveStylus(false) { - clearButtons(); -} - -void TouchButtonAccumulator::configure(InputDevice* device) { - mHaveBtnTouch = device->hasKey(BTN_TOUCH); - mHaveStylus = device->hasKey(BTN_TOOL_PEN) - || device->hasKey(BTN_TOOL_RUBBER) - || device->hasKey(BTN_TOOL_BRUSH) - || device->hasKey(BTN_TOOL_PENCIL) - || device->hasKey(BTN_TOOL_AIRBRUSH); -} - -void TouchButtonAccumulator::reset(InputDevice* device) { - mBtnTouch = device->isKeyPressed(BTN_TOUCH); - mBtnStylus = device->isKeyPressed(BTN_STYLUS); - // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch - mBtnStylus2 = - device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); - mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); - mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); - mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); - mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); - mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); - mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); - mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); - mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); - mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); - mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); - mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); -} - -void TouchButtonAccumulator::clearButtons() { - mBtnTouch = 0; - mBtnStylus = 0; - mBtnStylus2 = 0; - mBtnToolFinger = 0; - mBtnToolPen = 0; - mBtnToolRubber = 0; - mBtnToolBrush = 0; - mBtnToolPencil = 0; - mBtnToolAirbrush = 0; - mBtnToolMouse = 0; - mBtnToolLens = 0; - mBtnToolDoubleTap = 0; - mBtnToolTripleTap = 0; - mBtnToolQuadTap = 0; -} - -void TouchButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_TOUCH: - mBtnTouch = rawEvent->value; - break; - case BTN_STYLUS: - mBtnStylus = rawEvent->value; - break; - case BTN_STYLUS2: - case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch - mBtnStylus2 = rawEvent->value; - break; - case BTN_TOOL_FINGER: - mBtnToolFinger = rawEvent->value; - break; - case BTN_TOOL_PEN: - mBtnToolPen = rawEvent->value; - break; - case BTN_TOOL_RUBBER: - mBtnToolRubber = rawEvent->value; - break; - case BTN_TOOL_BRUSH: - mBtnToolBrush = rawEvent->value; - break; - case BTN_TOOL_PENCIL: - mBtnToolPencil = rawEvent->value; - break; - case BTN_TOOL_AIRBRUSH: - mBtnToolAirbrush = rawEvent->value; - break; - case BTN_TOOL_MOUSE: - mBtnToolMouse = rawEvent->value; - break; - case BTN_TOOL_LENS: - mBtnToolLens = rawEvent->value; - break; - case BTN_TOOL_DOUBLETAP: - mBtnToolDoubleTap = rawEvent->value; - break; - case BTN_TOOL_TRIPLETAP: - mBtnToolTripleTap = rawEvent->value; - break; - case BTN_TOOL_QUADTAP: - mBtnToolQuadTap = rawEvent->value; - break; - } - } -} - -uint32_t TouchButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnStylus) { - result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY; - } - if (mBtnStylus2) { - result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY; - } - return result; -} - -int32_t TouchButtonAccumulator::getToolType() const { - if (mBtnToolMouse || mBtnToolLens) { - return AMOTION_EVENT_TOOL_TYPE_MOUSE; - } - if (mBtnToolRubber) { - return AMOTION_EVENT_TOOL_TYPE_ERASER; - } - if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { - return AMOTION_EVENT_TOOL_TYPE_FINGER; - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - -bool TouchButtonAccumulator::isToolActive() const { - return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber - || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush - || mBtnToolMouse || mBtnToolLens - || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; -} - -bool TouchButtonAccumulator::isHovering() const { - return mHaveBtnTouch && !mBtnTouch; -} - -bool TouchButtonAccumulator::hasStylus() const { - return mHaveStylus; -} - - -// --- RawPointerAxes --- - -RawPointerAxes::RawPointerAxes() { - clear(); -} - -void RawPointerAxes::clear() { - x.clear(); - y.clear(); - pressure.clear(); - touchMajor.clear(); - touchMinor.clear(); - toolMajor.clear(); - toolMinor.clear(); - orientation.clear(); - distance.clear(); - tiltX.clear(); - tiltY.clear(); - trackingId.clear(); - slot.clear(); -} - - -// --- RawPointerData --- - -RawPointerData::RawPointerData() { - clear(); -} - -void RawPointerData::clear() { - pointerCount = 0; - clearIdBits(); -} - -void RawPointerData::copyFrom(const RawPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointers[i] = other.pointers[i]; - - int id = pointers[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - -void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { - float x = 0, y = 0; - uint32_t count = touchingIdBits.count(); - if (count) { - for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const Pointer& pointer = pointerForId(id); - x += pointer.x; - y += pointer.y; - } - x /= count; - y /= count; - } - *outX = x; - *outY = y; -} - - -// --- CookedPointerData --- - -CookedPointerData::CookedPointerData() { - clear(); -} - -void CookedPointerData::clear() { - pointerCount = 0; - hoveringIdBits.clear(); - touchingIdBits.clear(); -} - -void CookedPointerData::copyFrom(const CookedPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - - int id = pointerProperties[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - - -// --- SingleTouchMotionAccumulator --- - -SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { - clearAbsoluteAxes(); -} - -void SingleTouchMotionAccumulator::reset(InputDevice* device) { - mAbsX = device->getAbsoluteAxisValue(ABS_X); - mAbsY = device->getAbsoluteAxisValue(ABS_Y); - mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); - mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); - mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); - mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); - mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); -} - -void SingleTouchMotionAccumulator::clearAbsoluteAxes() { - mAbsX = 0; - mAbsY = 0; - mAbsPressure = 0; - mAbsToolWidth = 0; - mAbsDistance = 0; - mAbsTiltX = 0; - mAbsTiltY = 0; -} - -void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - switch (rawEvent->code) { - case ABS_X: - mAbsX = rawEvent->value; - break; - case ABS_Y: - mAbsY = rawEvent->value; - break; - case ABS_PRESSURE: - mAbsPressure = rawEvent->value; - break; - case ABS_TOOL_WIDTH: - mAbsToolWidth = rawEvent->value; - break; - case ABS_DISTANCE: - mAbsDistance = rawEvent->value; - break; - case ABS_TILT_X: - mAbsTiltX = rawEvent->value; - break; - case ABS_TILT_Y: - mAbsTiltY = rawEvent->value; - break; - } - } -} - - -// --- MultiTouchMotionAccumulator --- - -MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : - mCurrentSlot(-1), mSlots(nullptr), mSlotCount(0), mUsingSlotsProtocol(false), - mHaveStylus(false), mDeviceTimestamp(0) { -} - -MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { - delete[] mSlots; -} - -void MultiTouchMotionAccumulator::configure(InputDevice* device, - size_t slotCount, bool usingSlotsProtocol) { - mSlotCount = slotCount; - mUsingSlotsProtocol = usingSlotsProtocol; - mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - - delete[] mSlots; - mSlots = new Slot[slotCount]; -} - -void MultiTouchMotionAccumulator::reset(InputDevice* device) { - // Unfortunately there is no way to read the initial contents of the slots. - // So when we reset the accumulator, we must assume they are all zeroes. - if (mUsingSlotsProtocol) { - // Query the driver for the current slot index and use it as the initial slot - // before we start reading events from the device. It is possible that the - // current slot index will not be the same as it was when the first event was - // written into the evdev buffer, which means the input mapper could start - // out of sync with the initial state of the events in the evdev buffer. - // In the extremely unlikely case that this happens, the data from - // two slots will be confused until the next ABS_MT_SLOT event is received. - // This can cause the touch point to "jump", but at least there will be - // no stuck touches. - int32_t initialSlot; - status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), - ABS_MT_SLOT, &initialSlot); - if (status) { - ALOGD("Could not retrieve current multitouch slot index. status=%d", status); - initialSlot = -1; - } - clearSlots(initialSlot); - } else { - clearSlots(-1); - } - mDeviceTimestamp = 0; -} - -void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - if (mSlots) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); - } - } - mCurrentSlot = initialSlot; -} - -void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - bool newSlot = false; - if (mUsingSlotsProtocol) { - if (rawEvent->code == ABS_MT_SLOT) { - mCurrentSlot = rawEvent->value; - newSlot = true; - } - } else if (mCurrentSlot < 0) { - mCurrentSlot = 0; - } - - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { -#if DEBUG_POINTERS - if (newSlot) { - ALOGW("MultiTouch device emitted invalid slot index %d but it " - "should be between 0 and %zd; ignoring this slot.", - mCurrentSlot, mSlotCount - 1); - } -#endif - } else { - Slot* slot = &mSlots[mCurrentSlot]; - - switch (rawEvent->code) { - case ABS_MT_POSITION_X: - slot->mInUse = true; - slot->mAbsMTPositionX = rawEvent->value; - break; - case ABS_MT_POSITION_Y: - slot->mInUse = true; - slot->mAbsMTPositionY = rawEvent->value; - break; - case ABS_MT_TOUCH_MAJOR: - slot->mInUse = true; - slot->mAbsMTTouchMajor = rawEvent->value; - break; - case ABS_MT_TOUCH_MINOR: - slot->mInUse = true; - slot->mAbsMTTouchMinor = rawEvent->value; - slot->mHaveAbsMTTouchMinor = true; - break; - case ABS_MT_WIDTH_MAJOR: - slot->mInUse = true; - slot->mAbsMTWidthMajor = rawEvent->value; - break; - case ABS_MT_WIDTH_MINOR: - slot->mInUse = true; - slot->mAbsMTWidthMinor = rawEvent->value; - slot->mHaveAbsMTWidthMinor = true; - break; - case ABS_MT_ORIENTATION: - slot->mInUse = true; - slot->mAbsMTOrientation = rawEvent->value; - break; - case ABS_MT_TRACKING_ID: - if (mUsingSlotsProtocol && rawEvent->value < 0) { - // The slot is no longer in use but it retains its previous contents, - // which may be reused for subsequent touches. - slot->mInUse = false; - } else { - slot->mInUse = true; - slot->mAbsMTTrackingId = rawEvent->value; - } - break; - case ABS_MT_PRESSURE: - slot->mInUse = true; - slot->mAbsMTPressure = rawEvent->value; - break; - case ABS_MT_DISTANCE: - slot->mInUse = true; - slot->mAbsMTDistance = rawEvent->value; - break; - case ABS_MT_TOOL_TYPE: - slot->mInUse = true; - slot->mAbsMTToolType = rawEvent->value; - slot->mHaveAbsMTToolType = true; - break; - } - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { - // MultiTouch Sync: The driver has returned all data for *one* of the pointers. - mCurrentSlot += 1; - } else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) { - mDeviceTimestamp = rawEvent->value; - } -} - -void MultiTouchMotionAccumulator::finishSync() { - if (!mUsingSlotsProtocol) { - clearSlots(-1); - } -} - -bool MultiTouchMotionAccumulator::hasStylus() const { - return mHaveStylus; -} - - -// --- MultiTouchMotionAccumulator::Slot --- - -MultiTouchMotionAccumulator::Slot::Slot() { - clear(); -} - -void MultiTouchMotionAccumulator::Slot::clear() { - mInUse = false; - mHaveAbsMTTouchMinor = false; - mHaveAbsMTWidthMinor = false; - mHaveAbsMTToolType = false; - mAbsMTPositionX = 0; - mAbsMTPositionY = 0; - mAbsMTTouchMajor = 0; - mAbsMTTouchMinor = 0; - mAbsMTWidthMajor = 0; - mAbsMTWidthMinor = 0; - mAbsMTOrientation = 0; - mAbsMTTrackingId = -1; - mAbsMTPressure = 0; - mAbsMTDistance = 0; - mAbsMTToolType = 0; -} - -int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { - if (mHaveAbsMTToolType) { - switch (mAbsMTToolType) { - case MT_TOOL_FINGER: - return AMOTION_EVENT_TOOL_TYPE_FINGER; - case MT_TOOL_PEN: - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - - -// --- InputMapper --- - -InputMapper::InputMapper(InputDevice* device) : - mDevice(device), mContext(device->getContext()) { -} - -InputMapper::~InputMapper() { -} - -void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { - info->addSource(getSources()); -} - -void InputMapper::dump(std::string& dump) { -} - -void InputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { -} - -void InputMapper::reset(nsecs_t when) { -} - -void InputMapper::timeoutExpired(nsecs_t when) { -} - -int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return AKEY_STATE_UNKNOWN; -} - -bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return false; -} - -void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -} - -void InputMapper::cancelVibrate(int32_t token) { -} - -void InputMapper::cancelTouch(nsecs_t when) { -} - -int32_t InputMapper::getMetaState() { - return 0; -} - -void InputMapper::updateMetaState(int32_t keyCode) { -} - -void InputMapper::updateExternalStylusState(const StylusState& state) { - -} - -void InputMapper::fadePointer() { -} - -status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { - return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); -} - -void InputMapper::bumpGeneration() { - mDevice->bumpGeneration(); -} - -void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump, - const RawAbsoluteAxisInfo& axis, const char* name) { - if (axis.valid) { - dump += StringPrintf(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", - name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); - } else { - dump += StringPrintf(INDENT4 "%s: unknown range\n", name); - } -} - -void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) { - dump += StringPrintf(INDENT4 "When: %" PRId64 "\n", state.when); - dump += StringPrintf(INDENT4 "Pressure: %f\n", state.pressure); - dump += StringPrintf(INDENT4 "Button State: 0x%08x\n", state.buttons); - dump += StringPrintf(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); -} - -// --- SwitchInputMapper --- - -SwitchInputMapper::SwitchInputMapper(InputDevice* device) : - InputMapper(device), mSwitchValues(0), mUpdatedSwitchMask(0) { -} - -SwitchInputMapper::~SwitchInputMapper() { -} - -uint32_t SwitchInputMapper::getSources() { - return AINPUT_SOURCE_SWITCH; -} - -void SwitchInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_SW: - processSwitch(rawEvent->code, rawEvent->value); - break; - - case EV_SYN: - if (rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } - } -} - -void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { - if (switchCode >= 0 && switchCode < 32) { - if (switchValue) { - mSwitchValues |= 1 << switchCode; - } else { - mSwitchValues &= ~(1 << switchCode); - } - mUpdatedSwitchMask |= 1 << switchCode; - } -} - -void SwitchInputMapper::sync(nsecs_t when) { - if (mUpdatedSwitchMask) { - uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask; - NotifySwitchArgs args(mContext->getNextSequenceNum(), when, 0, updatedSwitchValues, - mUpdatedSwitchMask); - getListener()->notifySwitch(&args); - - mUpdatedSwitchMask = 0; - } -} - -int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getEventHub()->getSwitchState(getDeviceId(), switchCode); -} - -void SwitchInputMapper::dump(std::string& dump) { - dump += INDENT2 "Switch Input Mapper:\n"; - dump += StringPrintf(INDENT3 "SwitchValues: %x\n", mSwitchValues); -} - -// --- VibratorInputMapper --- - -VibratorInputMapper::VibratorInputMapper(InputDevice* device) : - InputMapper(device), mVibrating(false) { -} - -VibratorInputMapper::~VibratorInputMapper() { -} - -uint32_t VibratorInputMapper::getSources() { - return 0; -} - -void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setVibrator(true); -} - -void VibratorInputMapper::process(const RawEvent* rawEvent) { - // TODO: Handle FF_STATUS, although it does not seem to be widely supported. -} - -void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -#if DEBUG_VIBRATOR - std::string patternStr; - for (size_t i = 0; i < patternSize; i++) { - if (i != 0) { - patternStr += ", "; - } - patternStr += StringPrintf("%" PRId64, pattern[i]); - } - ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", - getDeviceId(), patternStr.c_str(), repeat, token); -#endif - - mVibrating = true; - memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); - mPatternSize = patternSize; - mRepeat = repeat; - mToken = token; - mIndex = -1; - - nextStep(); -} - -void VibratorInputMapper::cancelVibrate(int32_t token) { -#if DEBUG_VIBRATOR - ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); -#endif - - if (mVibrating && mToken == token) { - stopVibrating(); - } -} - -void VibratorInputMapper::timeoutExpired(nsecs_t when) { - if (mVibrating) { - if (when >= mNextStepTime) { - nextStep(); - } else { - getContext()->requestTimeoutAtTime(mNextStepTime); - } - } -} - -void VibratorInputMapper::nextStep() { - mIndex += 1; - if (size_t(mIndex) >= mPatternSize) { - if (mRepeat < 0) { - // We are done. - stopVibrating(); - return; - } - mIndex = mRepeat; - } - - bool vibratorOn = mIndex & 1; - nsecs_t duration = mPattern[mIndex]; - if (vibratorOn) { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration); -#endif - getEventHub()->vibrate(getDeviceId(), duration); - } else { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); - } - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - mNextStepTime = now + duration; - getContext()->requestTimeoutAtTime(mNextStepTime); -#if DEBUG_VIBRATOR - ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); -#endif -} - -void VibratorInputMapper::stopVibrating() { - mVibrating = false; -#if DEBUG_VIBRATOR - ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); -} - -void VibratorInputMapper::dump(std::string& dump) { - dump += INDENT2 "Vibrator Input Mapper:\n"; - dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating)); -} - - -// --- KeyboardInputMapper --- - -KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, - uint32_t source, int32_t keyboardType) : - InputMapper(device), mSource(source), mKeyboardType(keyboardType) { -} - -KeyboardInputMapper::~KeyboardInputMapper() { -} - -uint32_t KeyboardInputMapper::getSources() { - return mSource; -} - -int32_t KeyboardInputMapper::getOrientation() { - if (mViewport) { - return mViewport->orientation; - } - return DISPLAY_ORIENTATION_0; -} - -int32_t KeyboardInputMapper::getDisplayId() { - if (mViewport) { - return mViewport->displayId; - } - return ADISPLAY_ID_NONE; -} - -void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setKeyboardType(mKeyboardType); - info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); -} - -void KeyboardInputMapper::dump(std::string& dump) { - dump += INDENT2 "Keyboard Input Mapper:\n"; - dumpParameters(dump); - dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType); - dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation()); - dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); - dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState); - dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); -} - -void KeyboardInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware) { - mViewport = config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - } - } -} - -static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const *property) { - int32_t mapped = 0; - if (config.tryGetProperty(String8(property), mapped) && mapped > 0) { - for (size_t i = 0; i < stemKeyRotationMapSize; i++) { - if (stemKeyRotationMap[i][0] == keyCode) { - stemKeyRotationMap[i][1] = mapped; - return; - } - } - } -} - -void KeyboardInputMapper::configureParameters() { - mParameters.orientationAware = false; - const PropertyMap& config = getDevice()->getConfiguration(); - config.tryGetProperty(String8("keyboard.orientationAware"), - mParameters.orientationAware); - - if (mParameters.orientationAware) { - mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary"); - mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1"); - mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2"); - mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3"); - } - - mParameters.handlesKeyRepeat = false; - config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), - mParameters.handlesKeyRepeat); -} - -void KeyboardInputMapper::dumpParameters(std::string& dump) { - dump += INDENT3 "Parameters:\n"; - dump += StringPrintf(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); - dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", - toString(mParameters.handlesKeyRepeat)); -} - -void KeyboardInputMapper::reset(nsecs_t when) { - mMetaState = AMETA_NONE; - mDownTime = 0; - mKeyDowns.clear(); - mCurrentHidUsage = 0; - - resetLedState(); - - InputMapper::reset(when); -} - -void KeyboardInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_KEY: { - int32_t scanCode = rawEvent->code; - int32_t usageCode = mCurrentHidUsage; - mCurrentHidUsage = 0; - - if (isKeyboardOrGamepadKey(scanCode)) { - processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode); - } - break; - } - case EV_MSC: { - if (rawEvent->code == MSC_SCAN) { - mCurrentHidUsage = rawEvent->value; - } - break; - } - case EV_SYN: { - if (rawEvent->code == SYN_REPORT) { - mCurrentHidUsage = 0; - } - } - } -} - -bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { - return scanCode < BTN_MOUSE - || scanCode >= KEY_OK - || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) - || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); -} - -bool KeyboardInputMapper::isMediaKey(int32_t keyCode) { - switch (keyCode) { - case AKEYCODE_MEDIA_PLAY: - case AKEYCODE_MEDIA_PAUSE: - case AKEYCODE_MEDIA_PLAY_PAUSE: - case AKEYCODE_MUTE: - case AKEYCODE_HEADSETHOOK: - case AKEYCODE_MEDIA_STOP: - case AKEYCODE_MEDIA_NEXT: - case AKEYCODE_MEDIA_PREVIOUS: - case AKEYCODE_MEDIA_REWIND: - case AKEYCODE_MEDIA_RECORD: - case AKEYCODE_MEDIA_FAST_FORWARD: - case AKEYCODE_MEDIA_SKIP_FORWARD: - case AKEYCODE_MEDIA_SKIP_BACKWARD: - case AKEYCODE_MEDIA_STEP_FORWARD: - case AKEYCODE_MEDIA_STEP_BACKWARD: - case AKEYCODE_MEDIA_AUDIO_TRACK: - case AKEYCODE_VOLUME_UP: - case AKEYCODE_VOLUME_DOWN: - case AKEYCODE_VOLUME_MUTE: - case AKEYCODE_TV_AUDIO_DESCRIPTION: - case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: - case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: - return true; - } - return false; -} - -void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, - int32_t usageCode) { - int32_t keyCode; - int32_t keyMetaState; - uint32_t policyFlags; - - if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState, - &keyCode, &keyMetaState, &policyFlags)) { - keyCode = AKEYCODE_UNKNOWN; - keyMetaState = mMetaState; - policyFlags = 0; - } - - if (down) { - // Rotate key codes according to orientation if needed. - if (mParameters.orientationAware) { - keyCode = rotateKeyCode(keyCode, getOrientation()); - } - - // Add key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key repeat, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns[keyDownIndex].keyCode; - } else { - // key down - if ((policyFlags & POLICY_FLAG_VIRTUAL) - && mContext->shouldDropVirtualKey(when, - getDevice(), keyCode, scanCode)) { - return; - } - if (policyFlags & POLICY_FLAG_GESTURE) { - mDevice->cancelTouch(when); - } - - KeyDown keyDown; - keyDown.keyCode = keyCode; - keyDown.scanCode = scanCode; - mKeyDowns.push_back(keyDown); - } - - mDownTime = when; - } else { - // Remove key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key up, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns[keyDownIndex].keyCode; - mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex); - } else { - // key was not actually down - ALOGI("Dropping key up from device %s because the key was not down. " - "keyCode=%d, scanCode=%d", - getDeviceName().c_str(), keyCode, scanCode); - return; - } - } - - if (updateMetaStateIfNeeded(keyCode, down)) { - // If global meta state changed send it along with the key. - // If it has not changed then we'll use what keymap gave us, - // since key replacement logic might temporarily reset a few - // meta bits for given key. - keyMetaState = mMetaState; - } - - nsecs_t downTime = mDownTime; - - // Key down on external an keyboard should wake the device. - // We don't do this for internal keyboards to prevent them from waking up in your pocket. - // For internal keyboards, the key layout file should specify the policy flags for - // each wake key individually. - // TODO: Use the input device configuration to control this behavior more finely. - if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) { - policyFlags |= POLICY_FLAG_WAKE; - } - - if (mParameters.handlesKeyRepeat) { - policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; - } - - NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); - getListener()->notifyKey(&args); -} - -ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { - size_t n = mKeyDowns.size(); - for (size_t i = 0; i < n; i++) { - if (mKeyDowns[i].scanCode == scanCode) { - return i; - } - } - return -1; -} - -int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); -} - -int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); -} - -bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); -} - -int32_t KeyboardInputMapper::getMetaState() { - return mMetaState; -} - -void KeyboardInputMapper::updateMetaState(int32_t keyCode) { - updateMetaStateIfNeeded(keyCode, false); -} - -bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) { - int32_t oldMetaState = mMetaState; - int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState); - bool metaStateChanged = oldMetaState != newMetaState; - if (metaStateChanged) { - mMetaState = newMetaState; - updateLedState(false); - - getContext()->updateGlobalMetaState(); - } - - return metaStateChanged; -} - -void KeyboardInputMapper::resetLedState() { - initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK); - initializeLedState(mNumLockLedState, ALED_NUM_LOCK); - initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK); - - updateLedState(true); -} - -void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { - ledState.avail = getEventHub()->hasLed(getDeviceId(), led); - ledState.on = false; -} - -void KeyboardInputMapper::updateLedState(bool reset) { - updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, - AMETA_CAPS_LOCK_ON, reset); - updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, - AMETA_NUM_LOCK_ON, reset); - updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, - AMETA_SCROLL_LOCK_ON, reset); -} - -void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, - int32_t led, int32_t modifier, bool reset) { - if (ledState.avail) { - bool desiredState = (mMetaState & modifier) != 0; - if (reset || ledState.on != desiredState) { - getEventHub()->setLedState(getDeviceId(), led, desiredState); - ledState.on = desiredState; - } - } -} - - -// --- CursorInputMapper --- - -CursorInputMapper::CursorInputMapper(InputDevice* device) : - InputMapper(device) { -} - -CursorInputMapper::~CursorInputMapper() { -} - -uint32_t CursorInputMapper::getSources() { - return mSource; -} - -void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mParameters.mode == Parameters::MODE_POINTER) { - float minX, minY, maxX, maxY; - if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f); - } - } else { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); - } - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } -} - -void CursorInputMapper::dump(std::string& dump) { - dump += INDENT2 "Cursor Input Mapper:\n"; - dumpParameters(dump); - dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale); - dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale); - dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision); - dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision); - dump += StringPrintf(INDENT3 "HaveVWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeVWheel())); - dump += StringPrintf(INDENT3 "HaveHWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeHWheel())); - dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); - dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); - dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation); - dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState); - dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); - dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); -} - -void CursorInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - mCursorScrollAccumulator.configure(getDevice()); - - // Configure basic parameters. - configureParameters(); - - // Configure device mode. - switch (mParameters.mode) { - case Parameters::MODE_POINTER_RELATIVE: - // Should not happen during first time configuration. - ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER"); - mParameters.mode = Parameters::MODE_POINTER; - [[fallthrough]]; - case Parameters::MODE_POINTER: - mSource = AINPUT_SOURCE_MOUSE; - mXPrecision = 1.0f; - mYPrecision = 1.0f; - mXScale = 1.0f; - mYScale = 1.0f; - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - break; - case Parameters::MODE_NAVIGATION: - mSource = AINPUT_SOURCE_TRACKBALL; - mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - break; - } - - mVWheelScale = 1.0f; - mHWheelScale = 1.0f; - } - - if ((!changes && config->pointerCapture) - || (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) { - if (config->pointerCapture) { - if (mParameters.mode == Parameters::MODE_POINTER) { - mParameters.mode = Parameters::MODE_POINTER_RELATIVE; - mSource = AINPUT_SOURCE_MOUSE_RELATIVE; - // Keep PointerController around in order to preserve the pointer position. - mPointerController->fade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else { - ALOGE("Cannot request pointer capture, device is not in MODE_POINTER"); - } - } else { - if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) { - mParameters.mode = Parameters::MODE_POINTER; - mSource = AINPUT_SOURCE_MOUSE; - } else { - ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE"); - } - } - bumpGeneration(); - if (changes) { - getDevice()->notifyReset(when); - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - mOrientation = DISPLAY_ORIENTATION_0; - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - std::optional<DisplayViewport> internalViewport = - config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - if (internalViewport) { - mOrientation = internalViewport->orientation; - } - } - - // Update the PointerController if viewports changed. - if (mParameters.mode == Parameters::MODE_POINTER) { - getPolicy()->obtainPointerController(getDeviceId()); - } - bumpGeneration(); - } -} - -void CursorInputMapper::configureParameters() { - mParameters.mode = Parameters::MODE_POINTER; - String8 cursorModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { - if (cursorModeString == "navigation") { - mParameters.mode = Parameters::MODE_NAVIGATION; - } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); - } - } - - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; - } -} - -void CursorInputMapper::dumpParameters(std::string& dump) { - dump += INDENT3 "Parameters:\n"; - dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n", - toString(mParameters.hasAssociatedDisplay)); - - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - dump += INDENT4 "Mode: pointer\n"; - break; - case Parameters::MODE_POINTER_RELATIVE: - dump += INDENT4 "Mode: relative pointer\n"; - break; - case Parameters::MODE_NAVIGATION: - dump += INDENT4 "Mode: navigation\n"; - break; - default: - ALOG_ASSERT(false); - } - - dump += StringPrintf(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void CursorInputMapper::reset(nsecs_t when) { - mButtonState = 0; - mDownTime = 0; - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mCursorButtonAccumulator.reset(getDevice()); - mCursorMotionAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - - InputMapper::reset(when); -} - -void CursorInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorMotionAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void CursorInputMapper::sync(nsecs_t when) { - int32_t lastButtonState = mButtonState; - int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); - mButtonState = currentButtonState; - - bool wasDown = isPointerDown(lastButtonState); - bool down = isPointerDown(currentButtonState); - bool downChanged; - if (!wasDown && down) { - mDownTime = when; - downChanged = true; - } else if (wasDown && !down) { - downChanged = true; - } else { - downChanged = false; - } - nsecs_t downTime = mDownTime; - bool buttonsChanged = currentButtonState != lastButtonState; - int32_t buttonsPressed = currentButtonState & ~lastButtonState; - int32_t buttonsReleased = lastButtonState & ~currentButtonState; - - float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; - float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; - bool moved = deltaX != 0 || deltaY != 0; - - // Rotate delta according to orientation if needed. - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay - && (deltaX != 0.0f || deltaY != 0.0f)) { - rotateDelta(mOrientation, &deltaX, &deltaY); - } - - // Move the pointer. - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); - float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); - bool scrolled = vscroll != 0 || hscroll != 0; - - mWheelYVelocityControl.move(when, nullptr, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, nullptr); - - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - int32_t displayId; - if (mSource == AINPUT_SOURCE_MOUSE) { - if (moved || scrolled || buttonsChanged) { - mPointerController->setPresentation( - PointerControllerInterface::PRESENTATION_POINTER); - - if (moved) { - mPointerController->move(deltaX, deltaY); - } - - if (buttonsChanged) { - mPointerController->setButtonState(currentButtonState); - } - - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - - float x, y; - mPointerController->getPosition(&x, &y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); - displayId = mPointerController->getDisplayId(); - } else { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); - displayId = ADISPLAY_ID_NONE; - } - - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - - // Moving an external trackball or mouse should wake the device. - // We don't do this for internal cursor devices to prevent them from waking up - // the device in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE; - } - - // Synthesize key down from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - displayId, policyFlags, lastButtonState, currentButtonState); - - // Send motion event. - if (downChanged || moved || scrolled || buttonsChanged) { - int32_t metaState = mContext->getGlobalMetaState(); - int32_t buttonState = lastButtonState; - int32_t motionEventAction; - if (downChanged) { - motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) { - motionEventAction = AMOTION_EVENT_ACTION_MOVE; - } else { - motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; - } - - if (buttonsReleased) { - BitSet32 released(buttonsReleased); - while (!released.isEmpty()) { - int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); - buttonState &= ~actionButton; - NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, - metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&releaseArgs); - } - } - - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - - if (buttonsPressed) { - BitSet32 pressed(buttonsPressed); - while (!pressed.isEmpty()) { - int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); - buttonState |= actionButton; - NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, - actionButton, 0, metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&pressArgs); - } - } - - ALOG_ASSERT(buttonState == currentButtonState); - - // Send hover move after UP to tell the application that the mouse is hovering now. - if (motionEventAction == AMOTION_EVENT_ACTION_UP - && (mSource == AINPUT_SOURCE_MOUSE)) { - NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&hoverArgs); - } - - // Send scroll events. - if (scrolled) { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&scrollArgs); - } - } - - // Synthesize key up from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - displayId, policyFlags, lastButtonState, currentButtonState); - - mCursorMotionAccumulator.finishSync(); - mCursorScrollAccumulator.finishSync(); -} - -int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); - } else { - return AKEY_STATE_UNKNOWN; - } -} - -void CursorInputMapper::fadePointer() { - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - -std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() { - if (mParameters.hasAssociatedDisplay) { - if (mParameters.mode == Parameters::MODE_POINTER) { - return std::make_optional(mPointerController->getDisplayId()); - } else { - // If the device is orientationAware and not a mouse, - // it expects to dispatch events to any display - return std::make_optional(ADISPLAY_ID_NONE); - } - } - return std::nullopt; -} - -// --- RotaryEncoderInputMapper --- - -RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) : - InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) { - mSource = AINPUT_SOURCE_ROTARY_ENCODER; -} - -RotaryEncoderInputMapper::~RotaryEncoderInputMapper() { -} - -uint32_t RotaryEncoderInputMapper::getSources() { - return mSource; -} - -void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { - float res = 0.0f; - if (!mDevice->getConfiguration().tryGetProperty(String8("device.res"), res)) { - ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); - } - if (!mDevice->getConfiguration().tryGetProperty(String8("device.scalingFactor"), - mScalingFactor)) { - ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," - "default to 1.0!\n"); - mScalingFactor = 1.0f; - } - info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - res * mScalingFactor); - } -} - -void RotaryEncoderInputMapper::dump(std::string& dump) { - dump += INDENT2 "Rotary Encoder Input Mapper:\n"; - dump += StringPrintf(INDENT3 "HaveWheel: %s\n", - toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel())); -} - -void RotaryEncoderInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - if (!changes) { - mRotaryEncoderScrollAccumulator.configure(getDevice()); - } - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - std::optional<DisplayViewport> internalViewport = - config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - if (internalViewport) { - mOrientation = internalViewport->orientation; - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } -} - -void RotaryEncoderInputMapper::reset(nsecs_t when) { - mRotaryEncoderScrollAccumulator.reset(getDevice()); - - InputMapper::reset(when); -} - -void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) { - mRotaryEncoderScrollAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void RotaryEncoderInputMapper::sync(nsecs_t when) { - PointerCoords pointerCoords; - pointerCoords.clear(); - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - - float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); - bool scrolled = scroll != 0; - - // This is not a pointer, so it's not associated with a display. - int32_t displayId = ADISPLAY_ID_NONE; - - // Moving the rotary encoder should wake the device (if specified). - uint32_t policyFlags = 0; - if (scrolled && getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE; - } - - if (mOrientation == DISPLAY_ORIENTATION_180) { - scroll = -scroll; - } - - // Send motion event. - if (scrolled) { - int32_t metaState = mContext->getGlobalMetaState(); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); - - NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - 0, 0, 0, /* videoFrames */ {}); - getListener()->notifyMotion(&scrollArgs); - } - - mRotaryEncoderScrollAccumulator.finishSync(); -} - -// --- TouchInputMapper --- - -TouchInputMapper::TouchInputMapper(InputDevice* device) : - InputMapper(device), - mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), - mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0), - mPhysicalWidth(-1), mPhysicalHeight(-1), mPhysicalLeft(0), mPhysicalTop(0), - mSurfaceOrientation(DISPLAY_ORIENTATION_0) { -} - -TouchInputMapper::~TouchInputMapper() { -} - -uint32_t TouchInputMapper::getSources() { - return mSource; -} - -void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mDeviceMode != DEVICE_MODE_DISABLED) { - info->addMotionRange(mOrientedRanges.x); - info->addMotionRange(mOrientedRanges.y); - info->addMotionRange(mOrientedRanges.pressure); - - if (mOrientedRanges.haveSize) { - info->addMotionRange(mOrientedRanges.size); - } - - if (mOrientedRanges.haveTouchSize) { - info->addMotionRange(mOrientedRanges.touchMajor); - info->addMotionRange(mOrientedRanges.touchMinor); - } - - if (mOrientedRanges.haveToolSize) { - info->addMotionRange(mOrientedRanges.toolMajor); - info->addMotionRange(mOrientedRanges.toolMinor); - } - - if (mOrientedRanges.haveOrientation) { - info->addMotionRange(mOrientedRanges.orientation); - } - - if (mOrientedRanges.haveDistance) { - info->addMotionRange(mOrientedRanges.distance); - } - - if (mOrientedRanges.haveTilt) { - info->addMotionRange(mOrientedRanges.tilt); - } - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; - const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - } - info->setButtonUnderPad(mParameters.hasButtonUnderPad); - } -} - -void TouchInputMapper::dump(std::string& dump) { - dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode)); - dumpParameters(dump); - dumpVirtualKeys(dump); - dumpRawPointerAxes(dump); - dumpCalibration(dump); - dumpAffineTransformation(dump); - dumpSurface(dump); - - dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n"); - dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate); - dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate); - dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale); - dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale); - dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision); - dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision); - dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); - dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale); - dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale); - dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); - dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); - dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); - dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); - dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); - dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); - dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - - dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); - dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawState.rawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; - dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " - "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " - "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " - "toolType=%d, isHovering=%s\n", i, - pointer.id, pointer.x, pointer.y, pointer.pressure, - pointer.touchMajor, pointer.touchMinor, - pointer.toolMajor, pointer.toolMinor, - pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance, - pointer.toolType, toString(pointer.isHovering)); - } - - dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState); - dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedState.cookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = - mLastCookedState.cookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; - dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " - "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " - "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " - "toolType=%d, isHovering=%s\n", i, - pointerProperties.id, - pointerCoords.getX(), - pointerCoords.getY(), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), - pointerProperties.toolType, - toString(mLastCookedState.cookedPointerData.isHovering(i))); - } - - dump += INDENT3 "Stylus Fusion:\n"; - dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n", - toString(mExternalStylusConnected)); - dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); - dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", - mExternalStylusFusionTimeout); - dump += INDENT3 "External Stylus State:\n"; - dumpStylusState(dump, mExternalStylusState); - - if (mDeviceMode == DEVICE_MODE_POINTER) { - dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n"); - dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", - mPointerXMovementScale); - dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", - mPointerYMovementScale); - dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n", - mPointerXZoomScale); - dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n", - mPointerYZoomScale); - dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n", - mPointerGestureMaxSwipeWidth); - } -} - -const char* TouchInputMapper::modeToString(DeviceMode deviceMode) { - switch (deviceMode) { - case DEVICE_MODE_DISABLED: - return "disabled"; - case DEVICE_MODE_DIRECT: - return "direct"; - case DEVICE_MODE_UNSCALED: - return "unscaled"; - case DEVICE_MODE_NAVIGATION: - return "navigation"; - case DEVICE_MODE_POINTER: - return "pointer"; - } - return "unknown"; -} - -void TouchInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - mConfig = *config; - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - - // Configure common accumulators. - mCursorScrollAccumulator.configure(getDevice()); - mTouchButtonAccumulator.configure(getDevice()); - - // Configure absolute axis information. - configureRawPointerAxes(); - - // Prepare input device calibration. - parseCalibration(); - resolveCalibration(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { - // Update location calibration to reflect current settings - updateAffineTransformation(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - // Update pointer speed. - mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - } - - bool resetNeeded = false; - if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO - | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT - | InputReaderConfiguration::CHANGE_SHOW_TOUCHES - | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { - // Configure device sources, surface dimensions, orientation and - // scaling factors. - configureSurface(when, &resetNeeded); - } - - if (changes && resetNeeded) { - // Send reset, unless this is the first time the device has been configured, - // in which case the reader will call reset itself after all mappers are ready. - getDevice()->notifyReset(when); - } -} - -void TouchInputMapper::resolveExternalStylusPresence() { - std::vector<InputDeviceInfo> devices; - mContext->getExternalStylusDevices(devices); - mExternalStylusConnected = !devices.empty(); - - if (!mExternalStylusConnected) { - resetExternalStylus(); - } -} - -void TouchInputMapper::configureParameters() { - // Use the pointer presentation mode for devices that do not support distinct - // multitouch. The spot-based presentation relies on being able to accurately - // locate two or more fingers on the touch pad. - mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) - ? Parameters::GESTURE_MODE_SINGLE_TOUCH : Parameters::GESTURE_MODE_MULTI_TOUCH; - - String8 gestureModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), - gestureModeString)) { - if (gestureModeString == "single-touch") { - mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH; - } else if (gestureModeString == "multi-touch") { - mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH; - } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); - } - } - - if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { - // The device is a touch screen. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { - // The device is a pointing device like a track pad. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) - || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { - // The device is a cursor device with a touch pad attached. - // By default don't use the touch pad to move the pointer. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else { - // The device is a touch pad of unknown purpose. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } - - mParameters.hasButtonUnderPad= - getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD); - - String8 deviceTypeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), - deviceTypeString)) { - if (deviceTypeString == "touchScreen") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (deviceTypeString == "touchPad") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else if (deviceTypeString == "touchNavigation") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; - } else if (deviceTypeString == "pointer") { - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); - } - } - - mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - mParameters.associatedDisplayIsExternal = false; - if (mParameters.orientationAware - || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { - mParameters.hasAssociatedDisplay = true; - if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { - mParameters.associatedDisplayIsExternal = getDevice()->isExternal(); - String8 uniqueDisplayId; - getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"), - uniqueDisplayId); - mParameters.uniqueDisplayId = uniqueDisplayId.c_str(); - } - } - if (getDevice()->getAssociatedDisplayPort()) { - mParameters.hasAssociatedDisplay = true; - } - - // Initial downs on external touch devices should wake the device. - // Normally we don't do this for internal touch screens to prevent them from waking - // up in your pocket but you can enable it using the input device configuration. - mParameters.wake = getDevice()->isExternal(); - getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"), - mParameters.wake); -} - -void TouchInputMapper::dumpParameters(std::string& dump) { - dump += INDENT3 "Parameters:\n"; - - switch (mParameters.gestureMode) { - case Parameters::GESTURE_MODE_SINGLE_TOUCH: - dump += INDENT4 "GestureMode: single-touch\n"; - break; - case Parameters::GESTURE_MODE_MULTI_TOUCH: - dump += INDENT4 "GestureMode: multi-touch\n"; - break; - default: - assert(false); - } - - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - dump += INDENT4 "DeviceType: touchScreen\n"; - break; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - dump += INDENT4 "DeviceType: touchPad\n"; - break; - case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: - dump += INDENT4 "DeviceType: touchNavigation\n"; - break; - case Parameters::DEVICE_TYPE_POINTER: - dump += INDENT4 "DeviceType: pointer\n"; - break; - default: - ALOG_ASSERT(false); - } - - dump += StringPrintf( - INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, displayId='%s'\n", - toString(mParameters.hasAssociatedDisplay), - toString(mParameters.associatedDisplayIsExternal), - mParameters.uniqueDisplayId.c_str()); - dump += StringPrintf(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void TouchInputMapper::configureRawPointerAxes() { - mRawPointerAxes.clear(); -} - -void TouchInputMapper::dumpRawPointerAxes(std::string& dump) { - dump += INDENT3 "Raw Touch Axes:\n"; - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); -} - -bool TouchInputMapper::hasExternalStylus() const { - return mExternalStylusConnected; -} - -/** - * Determine which DisplayViewport to use. - * 1. If display port is specified, return the matching viewport. If matching viewport not - * found, then return. - * 2. If a device has associated display, get the matching viewport by either unique id or by - * the display type (internal or external). - * 3. Otherwise, use a non-display viewport. - */ -std::optional<DisplayViewport> TouchInputMapper::findViewport() { - if (mParameters.hasAssociatedDisplay) { - const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort(); - if (displayPort) { - // Find the viewport that contains the same port - std::optional<DisplayViewport> v = mConfig.getDisplayViewportByPort(*displayPort); - if (!v) { - ALOGW("Input device %s should be associated with display on port %" PRIu8 ", " - "but the corresponding viewport is not found.", - getDeviceName().c_str(), *displayPort); - } - return v; - } - - if (!mParameters.uniqueDisplayId.empty()) { - return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId); - } - - ViewportType viewportTypeToUse; - if (mParameters.associatedDisplayIsExternal) { - viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL; - } else { - viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL; - } - - std::optional<DisplayViewport> viewport = - mConfig.getDisplayViewportByType(viewportTypeToUse); - if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) { - ALOGW("Input device %s should be associated with external display, " - "fallback to internal one for the external viewport is not found.", - getDeviceName().c_str()); - viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); - } - - return viewport; - } - - DisplayViewport newViewport; - // Raw width and height in the natural orientation. - int32_t rawWidth = mRawPointerAxes.getRawWidth(); - int32_t rawHeight = mRawPointerAxes.getRawHeight(); - newViewport.setNonDisplayViewport(rawWidth, rawHeight); - return std::make_optional(newViewport); -} - -void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { - int32_t oldDeviceMode = mDeviceMode; - - resolveExternalStylusPresence(); - - // Determine device mode. - if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER - && mConfig.pointerGesturesEnabled) { - mSource = AINPUT_SOURCE_MOUSE; - mDeviceMode = DEVICE_MODE_POINTER; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - && mParameters.hasAssociatedDisplay) { - mSource = AINPUT_SOURCE_TOUCHSCREEN; - mDeviceMode = DEVICE_MODE_DIRECT; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - if (hasExternalStylus()) { - mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { - mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; - mDeviceMode = DEVICE_MODE_NAVIGATION; - } else { - mSource = AINPUT_SOURCE_TOUCHPAD; - mDeviceMode = DEVICE_MODE_UNSCALED; - } - - // Ensure we have valid X and Y axes. - if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { - ALOGW("Touch device '%s' did not report support for X or Y axis! " - "The device will be inoperable.", getDeviceName().c_str()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - - // Get associated display dimensions. - std::optional<DisplayViewport> newViewport = findViewport(); - if (!newViewport) { - ALOGI("Touch device '%s' could not query the properties of its associated " - "display. The device will be inoperable until the display size " - "becomes available.", - getDeviceName().c_str()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - - // Raw width and height in the natural orientation. - int32_t rawWidth = mRawPointerAxes.getRawWidth(); - int32_t rawHeight = mRawPointerAxes.getRawHeight(); - - bool viewportChanged = mViewport != *newViewport; - if (viewportChanged) { - mViewport = *newViewport; - - if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { - // Convert rotated viewport to natural surface coordinates. - int32_t naturalLogicalWidth, naturalLogicalHeight; - int32_t naturalPhysicalWidth, naturalPhysicalHeight; - int32_t naturalPhysicalLeft, naturalPhysicalTop; - int32_t naturalDeviceWidth, naturalDeviceHeight; - switch (mViewport.orientation) { - case DISPLAY_ORIENTATION_90: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; - naturalPhysicalTop = mViewport.physicalLeft; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_180: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; - naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - case DISPLAY_ORIENTATION_270: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.physicalTop; - naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_0: - default: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.physicalLeft; - naturalPhysicalTop = mViewport.physicalTop; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - } - - if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) { - ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str()); - naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight; - naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth; - } - - mPhysicalWidth = naturalPhysicalWidth; - mPhysicalHeight = naturalPhysicalHeight; - mPhysicalLeft = naturalPhysicalLeft; - mPhysicalTop = naturalPhysicalTop; - - mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; - mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; - mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; - mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; - - mSurfaceOrientation = mParameters.orientationAware ? - mViewport.orientation : DISPLAY_ORIENTATION_0; - } else { - mPhysicalWidth = rawWidth; - mPhysicalHeight = rawHeight; - mPhysicalLeft = 0; - mPhysicalTop = 0; - - mSurfaceWidth = rawWidth; - mSurfaceHeight = rawHeight; - mSurfaceLeft = 0; - mSurfaceTop = 0; - mSurfaceOrientation = DISPLAY_ORIENTATION_0; - } - } - - // If moving between pointer modes, need to reset some state. - bool deviceModeChanged = mDeviceMode != oldDeviceMode; - if (deviceModeChanged) { - mOrientedRanges.clear(); - } - - // Create or update pointer controller if needed. - if (mDeviceMode == DEVICE_MODE_POINTER || - (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { - if (mPointerController == nullptr || viewportChanged) { - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - } - } else { - mPointerController.clear(); - } - - if (viewportChanged || deviceModeChanged) { - ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " - "display id %d", - getDeviceId(), getDeviceName().c_str(), mSurfaceWidth, mSurfaceHeight, - mSurfaceOrientation, mDeviceMode, mViewport.displayId); - - // Configure X and Y factors. - mXScale = float(mSurfaceWidth) / rawWidth; - mYScale = float(mSurfaceHeight) / rawHeight; - mXTranslate = -mSurfaceLeft; - mYTranslate = -mSurfaceTop; - mXPrecision = 1.0f / mXScale; - mYPrecision = 1.0f / mYScale; - - mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; - mOrientedRanges.x.source = mSource; - mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; - mOrientedRanges.y.source = mSource; - - configureVirtualKeys(); - - // Scale factor for terms that are not oriented in a particular axis. - // If the pixels are square then xScale == yScale otherwise we fake it - // by choosing an average. - mGeometricScale = avg(mXScale, mYScale); - - // Size of diagonal axis. - float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Size factors. - if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { - if (mRawPointerAxes.touchMajor.valid - && mRawPointerAxes.touchMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; - } else if (mRawPointerAxes.toolMajor.valid - && mRawPointerAxes.toolMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; - } else { - mSizeScale = 0.0f; - } - - mOrientedRanges.haveTouchSize = true; - mOrientedRanges.haveToolSize = true; - mOrientedRanges.haveSize = true; - - mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mSource; - mOrientedRanges.touchMajor.min = 0; - mOrientedRanges.touchMajor.max = diagonalSize; - mOrientedRanges.touchMajor.flat = 0; - mOrientedRanges.touchMajor.fuzz = 0; - mOrientedRanges.touchMajor.resolution = 0; - - mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; - mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; - - mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mSource; - mOrientedRanges.toolMajor.min = 0; - mOrientedRanges.toolMajor.max = diagonalSize; - mOrientedRanges.toolMajor.flat = 0; - mOrientedRanges.toolMajor.fuzz = 0; - mOrientedRanges.toolMajor.resolution = 0; - - mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; - mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; - - mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mSource; - mOrientedRanges.size.min = 0; - mOrientedRanges.size.max = 1.0; - mOrientedRanges.size.flat = 0; - mOrientedRanges.size.fuzz = 0; - mOrientedRanges.size.resolution = 0; - } else { - mSizeScale = 0.0f; - } - - // Pressure factors. - mPressureScale = 0; - float pressureMax = 1.0; - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL - || mCalibration.pressureCalibration - == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; - pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; - } else if (mRawPointerAxes.pressure.valid - && mRawPointerAxes.pressure.maxValue != 0) { - mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; - } - } - - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = pressureMax; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; - mOrientedRanges.pressure.resolution = 0; - - // Tilt - mTiltXCenter = 0; - mTiltXScale = 0; - mTiltYCenter = 0; - mTiltYScale = 0; - mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; - if (mHaveTilt) { - mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, - mRawPointerAxes.tiltX.maxValue); - mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, - mRawPointerAxes.tiltY.maxValue); - mTiltXScale = M_PI / 180; - mTiltYScale = M_PI / 180; - - mOrientedRanges.haveTilt = true; - - mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; - mOrientedRanges.tilt.source = mSource; - mOrientedRanges.tilt.min = 0; - mOrientedRanges.tilt.max = M_PI_2; - mOrientedRanges.tilt.flat = 0; - mOrientedRanges.tilt.fuzz = 0; - mOrientedRanges.tilt.resolution = 0; - } - - // Orientation - mOrientationScale = 0; - if (mHaveTilt) { - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI; - mOrientedRanges.orientation.max = M_PI; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } else if (mCalibration.orientationCalibration != - Calibration::ORIENTATION_CALIBRATION_NONE) { - if (mCalibration.orientationCalibration - == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { - if (mRawPointerAxes.orientation.valid) { - if (mRawPointerAxes.orientation.maxValue > 0) { - mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; - } else if (mRawPointerAxes.orientation.minValue < 0) { - mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; - } else { - mOrientationScale = 0; - } - } - } - - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } - - // Distance - mDistanceScale = 0; - if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { - if (mCalibration.distanceCalibration - == Calibration::DISTANCE_CALIBRATION_SCALED) { - if (mCalibration.haveDistanceScale) { - mDistanceScale = mCalibration.distanceScale; - } else { - mDistanceScale = 1.0f; - } - } - - mOrientedRanges.haveDistance = true; - - mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mSource; - mOrientedRanges.distance.min = - mRawPointerAxes.distance.minValue * mDistanceScale; - mOrientedRanges.distance.max = - mRawPointerAxes.distance.maxValue * mDistanceScale; - mOrientedRanges.distance.flat = 0; - mOrientedRanges.distance.fuzz = - mRawPointerAxes.distance.fuzz * mDistanceScale; - mOrientedRanges.distance.resolution = 0; - } - - // Compute oriented precision, scales and ranges. - // Note that the maximum value reported is an inclusive maximum value so it is one - // unit less than the total width or height of surface. - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - mOrientedXPrecision = mYPrecision; - mOrientedYPrecision = mXPrecision; - - mOrientedRanges.x.min = mYTranslate; - mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; - - mOrientedRanges.y.min = mXTranslate; - mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; - break; - - default: - mOrientedXPrecision = mXPrecision; - mOrientedYPrecision = mYPrecision; - - mOrientedRanges.x.min = mXTranslate; - mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; - - mOrientedRanges.y.min = mYTranslate; - mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; - break; - } - - // Location - updateAffineTransformation(); - - if (mDeviceMode == DEVICE_MODE_POINTER) { - // Compute pointer gesture detection parameters. - float rawDiagonal = hypotf(rawWidth, rawHeight); - float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Scale movements such that one whole swipe of the touch pad covers a - // given area relative to the diagonal size of the display when no acceleration - // is applied. - // Assume that the touch pad has a square aspect ratio such that movements in - // X and Y of the same number of raw units cover the same physical distance. - mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio - * displayDiagonal / rawDiagonal; - mPointerYMovementScale = mPointerXMovementScale; - - // Scale zooms to cover a smaller range of the display than movements do. - // This value determines the area around the pointer that is affected by freeform - // pointer gestures. - mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio - * displayDiagonal / rawDiagonal; - mPointerYZoomScale = mPointerXZoomScale; - - // Max width between pointers to detect a swipe gesture is more than some fraction - // of the diagonal axis of the touch pad. Touches that are wider than this are - // translated into freeform gestures. - mPointerGestureMaxSwipeWidth = - mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; - - // Abort current pointer usages because the state has changed. - abortPointerUsage(when, 0 /*policyFlags*/); - } - - // Inform the dispatcher about the changes. - *outResetNeeded = true; - bumpGeneration(); - } -} - -void TouchInputMapper::dumpSurface(std::string& dump) { - dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str()); - dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); - dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); - dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); - dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); - dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth); - dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight); - dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft); - dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop); - dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); -} - -void TouchInputMapper::configureVirtualKeys() { - std::vector<VirtualKeyDefinition> virtualKeyDefinitions; - getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); - - mVirtualKeys.clear(); - - if (virtualKeyDefinitions.size() == 0) { - return; - } - - int32_t touchScreenLeft = mRawPointerAxes.x.minValue; - int32_t touchScreenTop = mRawPointerAxes.y.minValue; - int32_t touchScreenWidth = mRawPointerAxes.getRawWidth(); - int32_t touchScreenHeight = mRawPointerAxes.getRawHeight(); - - for (const VirtualKeyDefinition& virtualKeyDefinition : virtualKeyDefinitions) { - VirtualKey virtualKey; - - virtualKey.scanCode = virtualKeyDefinition.scanCode; - int32_t keyCode; - int32_t dummyKeyMetaState; - uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0, - &keyCode, &dummyKeyMetaState, &flags)) { - ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", - virtualKey.scanCode); - continue; // drop the key - } - - virtualKey.keyCode = keyCode; - virtualKey.flags = flags; - - // convert the key definition's display coordinates into touch coordinates for a hit box - int32_t halfWidth = virtualKeyDefinition.width / 2; - int32_t halfHeight = virtualKeyDefinition.height / 2; - - virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - mVirtualKeys.push_back(virtualKey); - } -} - -void TouchInputMapper::dumpVirtualKeys(std::string& dump) { - if (!mVirtualKeys.empty()) { - dump += INDENT3 "Virtual Keys:\n"; - - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, " - "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", - i, virtualKey.scanCode, virtualKey.keyCode, - virtualKey.hitLeft, virtualKey.hitRight, - virtualKey.hitTop, virtualKey.hitBottom); - } - } -} - -void TouchInputMapper::parseCalibration() { - const PropertyMap& in = getDevice()->getConfiguration(); - Calibration& out = mCalibration; - - // Size - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; - String8 sizeCalibrationString; - if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { - if (sizeCalibrationString == "none") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } else if (sizeCalibrationString == "geometric") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } else if (sizeCalibrationString == "diameter") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; - } else if (sizeCalibrationString == "box") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX; - } else if (sizeCalibrationString == "area") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; - } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", - sizeCalibrationString.string()); - } - } - - out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), - out.sizeScale); - out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), - out.sizeBias); - out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), - out.sizeIsSummed); - - // Pressure - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; - String8 pressureCalibrationString; - if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { - if (pressureCalibrationString == "none") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } else if (pressureCalibrationString == "physical") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } else if (pressureCalibrationString == "amplitude") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; - } else if (pressureCalibrationString != "default") { - ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); - } - } - - out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), - out.pressureScale); - - // Orientation - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; - String8 orientationCalibrationString; - if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { - if (orientationCalibrationString == "none") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } else if (orientationCalibrationString == "interpolated") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } else if (orientationCalibrationString == "vector") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; - } else if (orientationCalibrationString != "default") { - ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); - } - } - - // Distance - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; - String8 distanceCalibrationString; - if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { - if (distanceCalibrationString == "none") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } else if (distanceCalibrationString == "scaled") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } else if (distanceCalibrationString != "default") { - ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); - } - } - - out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), - out.distanceScale); - - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; - String8 coverageCalibrationString; - if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { - if (coverageCalibrationString == "none") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } else if (coverageCalibrationString == "box") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; - } else if (coverageCalibrationString != "default") { - ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); - } - } -} - -void TouchInputMapper::resolveCalibration() { - // Size - if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } - } else { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } - - // Pressure - if (mRawPointerAxes.pressure.valid) { - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } - } else { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } - - // Orientation - if (mRawPointerAxes.orientation.valid) { - if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } - } else { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } - - // Distance - if (mRawPointerAxes.distance.valid) { - if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } - } else { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } - - // Coverage - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { - mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } -} - -void TouchInputMapper::dumpCalibration(std::string& dump) { - dump += INDENT3 "Calibration:\n"; - - // Size - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_NONE: - dump += INDENT4 "touch.size.calibration: none\n"; - break; - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - dump += INDENT4 "touch.size.calibration: geometric\n"; - break; - case Calibration::SIZE_CALIBRATION_DIAMETER: - dump += INDENT4 "touch.size.calibration: diameter\n"; - break; - case Calibration::SIZE_CALIBRATION_BOX: - dump += INDENT4 "touch.size.calibration: box\n"; - break; - case Calibration::SIZE_CALIBRATION_AREA: - dump += INDENT4 "touch.size.calibration: area\n"; - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveSizeScale) { - dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", - mCalibration.sizeScale); - } - - if (mCalibration.haveSizeBias) { - dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", - mCalibration.sizeBias); - } - - if (mCalibration.haveSizeIsSummed) { - dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n", - toString(mCalibration.sizeIsSummed)); - } - - // Pressure - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_NONE: - dump += INDENT4 "touch.pressure.calibration: none\n"; - break; - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - dump += INDENT4 "touch.pressure.calibration: physical\n"; - break; - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - dump += INDENT4 "touch.pressure.calibration: amplitude\n"; - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.havePressureScale) { - dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", - mCalibration.pressureScale); - } - - // Orientation - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_NONE: - dump += INDENT4 "touch.orientation.calibration: none\n"; - break; - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - dump += INDENT4 "touch.orientation.calibration: interpolated\n"; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: - dump += INDENT4 "touch.orientation.calibration: vector\n"; - break; - default: - ALOG_ASSERT(false); - } - - // Distance - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_NONE: - dump += INDENT4 "touch.distance.calibration: none\n"; - break; - case Calibration::DISTANCE_CALIBRATION_SCALED: - dump += INDENT4 "touch.distance.calibration: scaled\n"; - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveDistanceScale) { - dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", - mCalibration.distanceScale); - } - - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_NONE: - dump += INDENT4 "touch.coverage.calibration: none\n"; - break; - case Calibration::COVERAGE_CALIBRATION_BOX: - dump += INDENT4 "touch.coverage.calibration: box\n"; - break; - default: - ALOG_ASSERT(false); - } -} - -void TouchInputMapper::dumpAffineTransformation(std::string& dump) { - dump += INDENT3 "Affine Transformation:\n"; - - dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale); - dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix); - dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset); - dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix); - dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale); - dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset); -} - -void TouchInputMapper::updateAffineTransformation() { - mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(), - mSurfaceOrientation); -} - -void TouchInputMapper::reset(nsecs_t when) { - mCursorButtonAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - mTouchButtonAccumulator.reset(getDevice()); - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mRawStatesPending.clear(); - mCurrentRawState.clear(); - mCurrentCookedState.clear(); - mLastRawState.clear(); - mLastCookedState.clear(); - mPointerUsage = POINTER_USAGE_NONE; - mSentHoverEnter = false; - mHavePointerIds = false; - mCurrentMotionAborted = false; - mDownTime = 0; - - mCurrentVirtualKey.down = false; - - mPointerGesture.reset(); - mPointerSimple.reset(); - resetExternalStylus(); - - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } - - InputMapper::reset(when); -} - -void TouchInputMapper::resetExternalStylus() { - mExternalStylusState.clear(); - mExternalStylusId = -1; - mExternalStylusFusionTimeout = LLONG_MAX; - mExternalStylusDataPending = false; -} - -void TouchInputMapper::clearStylusDataPendingFlags() { - mExternalStylusDataPending = false; - mExternalStylusFusionTimeout = LLONG_MAX; -} - -void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) { - nsecs_t now = systemTime(CLOCK_MONOTONIC); - nsecs_t latency = now - evdevTime; - mStatistics.addValue(nanoseconds_to_microseconds(latency)); - nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime; - if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) { - android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, - mStatistics.min, mStatistics.max, - mStatistics.mean(), mStatistics.stdev(), mStatistics.count); - mStatistics.reset(now); - } -} - -void TouchInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - reportEventForStatistics(rawEvent->when); - sync(rawEvent->when); - } -} - -void TouchInputMapper::sync(nsecs_t when) { - const RawState* last = mRawStatesPending.empty() ? - &mCurrentRawState : &mRawStatesPending.back(); - - // Push a new state. - mRawStatesPending.emplace_back(); - - RawState* next = &mRawStatesPending.back(); - next->clear(); - next->when = when; - - // Sync button state. - next->buttonState = mTouchButtonAccumulator.getButtonState() - | mCursorButtonAccumulator.getButtonState(); - - // Sync scroll - next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); - mCursorScrollAccumulator.finishSync(); - - // Sync touch - syncTouch(when, next); - - // Assign pointer ids. - if (!mHavePointerIds) { - assignPointerIds(last, next); - } - -#if DEBUG_RAW_EVENTS - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - last->rawPointerData.pointerCount, - next->rawPointerData.pointerCount, - last->rawPointerData.touchingIdBits.value, - next->rawPointerData.touchingIdBits.value, - last->rawPointerData.hoveringIdBits.value, - next->rawPointerData.hoveringIdBits.value); -#endif - - processRawTouches(false /*timeout*/); -} - -void TouchInputMapper::processRawTouches(bool timeout) { - if (mDeviceMode == DEVICE_MODE_DISABLED) { - // Drop all input if the device is disabled. - mCurrentRawState.clear(); - mRawStatesPending.clear(); - return; - } - - // Drain any pending touch states. The invariant here is that the mCurrentRawState is always - // valid and must go through the full cook and dispatch cycle. This ensures that anything - // touching the current state will only observe the events that have been dispatched to the - // rest of the pipeline. - const size_t N = mRawStatesPending.size(); - size_t count; - for(count = 0; count < N; count++) { - const RawState& next = mRawStatesPending[count]; - - // A failure to assign the stylus id means that we're waiting on stylus data - // and so should defer the rest of the pipeline. - if (assignExternalStylusId(next, timeout)) { - break; - } - - // All ready to go. - clearStylusDataPendingFlags(); - mCurrentRawState.copyFrom(next); - if (mCurrentRawState.when < mLastRawState.when) { - mCurrentRawState.when = mLastRawState.when; - } - cookAndDispatch(mCurrentRawState.when); - } - if (count != 0) { - mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count); - } - - if (mExternalStylusDataPending) { - if (timeout) { - nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; - clearStylusDataPendingFlags(); - mCurrentRawState.copyFrom(mLastRawState); -#if DEBUG_STYLUS_FUSION - ALOGD("Timeout expired, synthesizing event with new stylus data"); -#endif - cookAndDispatch(when); - } else if (mExternalStylusFusionTimeout == LLONG_MAX) { - mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT; - getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); - } - } -} - -void TouchInputMapper::cookAndDispatch(nsecs_t when) { - // Always start with a clean state. - mCurrentCookedState.clear(); - - // Apply stylus buttons to current raw state. - applyExternalStylusButtonState(when); - - // Handle policy on initial down or hover events. - bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 - && mCurrentRawState.rawPointerData.pointerCount != 0; - - uint32_t policyFlags = 0; - bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } - - if (mParameters.wake) { - policyFlags |= POLICY_FLAG_WAKE; - } - } - - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawState.rawPointerData.clear(); - } - - // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); - - // Apply stylus pressure to current cooked state. - applyExternalStylusTouchState(when); - - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - mViewport.displayId, policyFlags, - mLastCookedState.buttonState, mCurrentCookedState.buttonState); - - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); - !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentCookedState.stylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentCookedState.fingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentCookedState.mouseIdBits.markBit(id); - } - } - for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); - !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentCookedState.stylusIdBits.markBit(id); - } - } - - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentCookedState.stylusIdBits.isEmpty()) { - mCurrentCookedState.mouseIdBits.clear(); - mCurrentCookedState.fingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { - mCurrentCookedState.fingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || - isPointerDown(mCurrentRawState.buttonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } - - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT - && mConfig.showTouches && mPointerController != nullptr) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentRawState.buttonState); - mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.touchingIdBits, - mViewport.displayId); - } - - if (!mCurrentMotionAborted) { - dispatchButtonRelease(when, policyFlags); - dispatchHoverExit(when, policyFlags); - dispatchTouches(when, policyFlags); - dispatchHoverEnterAndMove(when, policyFlags); - dispatchButtonPress(when, policyFlags); - } - - if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { - mCurrentMotionAborted = false; - } - } - - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - mViewport.displayId, policyFlags, - mLastCookedState.buttonState, mCurrentCookedState.buttonState); - - // Clear some transient state. - mCurrentRawState.rawVScroll = 0; - mCurrentRawState.rawHScroll = 0; - - // Copy current touch to last touch in preparation for the next cycle. - mLastRawState.copyFrom(mCurrentRawState); - mLastCookedState.copyFrom(mCurrentCookedState); -} - -void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { - if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) { - mCurrentRawState.buttonState |= mExternalStylusState.buttons; - } -} - -void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { - CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData; - const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData; - - if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) { - float pressure = mExternalStylusState.pressure; - if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) { - const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId); - pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - } - PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId); - coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - - PointerProperties& properties = - currentPointerData.editPointerPropertiesWithId(mExternalStylusId); - if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - properties.toolType = mExternalStylusState.toolType; - } - } -} - -bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { - if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { - return false; - } - - const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 - && state.rawPointerData.pointerCount != 0; - if (initialDown) { - if (mExternalStylusState.pressure != 0.0f) { -#if DEBUG_STYLUS_FUSION - ALOGD("Have both stylus and touch data, beginning fusion"); -#endif - mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); - } else if (timeout) { -#if DEBUG_STYLUS_FUSION - ALOGD("Timeout expired, assuming touch is not a stylus."); -#endif - resetExternalStylus(); - } else { - if (mExternalStylusFusionTimeout == LLONG_MAX) { - mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT; - } -#if DEBUG_STYLUS_FUSION - ALOGD("No stylus data but stylus is connected, requesting timeout " - "(%" PRId64 "ms)", mExternalStylusFusionTimeout); -#endif - getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); - return true; - } - } - - // Check if the stylus pointer has gone up. - if (mExternalStylusId != -1 && - !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { -#if DEBUG_STYLUS_FUSION - ALOGD("Stylus pointer is going up"); -#endif - mExternalStylusId = -1; - } - - return false; -} - -void TouchInputMapper::timeoutExpired(nsecs_t when) { - if (mDeviceMode == DEVICE_MODE_POINTER) { - if (mPointerUsage == POINTER_USAGE_GESTURES) { - dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); - } - } else if (mDeviceMode == DEVICE_MODE_DIRECT) { - if (mExternalStylusFusionTimeout < when) { - processRawTouches(true /*timeout*/); - } else if (mExternalStylusFusionTimeout != LLONG_MAX) { - getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); - } - } -} - -void TouchInputMapper::updateExternalStylusState(const StylusState& state) { - mExternalStylusState.copyFrom(state); - if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) { - // We're either in the middle of a fused stream of data or we're waiting on data before - // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus - // data. - mExternalStylusDataPending = true; - processRawTouches(false /*timeout*/); - } -} - -bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { - // Check for release of a virtual key. - if (mCurrentVirtualKey.down) { - if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { - // Pointer went up while virtual key was down. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - return true; - } - - if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(id); - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { - // Pointer is still within the space of the virtual key. - return true; - } - } - - // Pointer left virtual key area or another pointer also went down. - // Send key cancellation but do not consume the touch yet. - // This is useful when the user swipes through from the virtual key area - // into the main display surface. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY - | AKEY_EVENT_FLAG_CANCELED); - } - } - - if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() - && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { - // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); - if (!isPointInsideSurface(pointer.x, pointer.y)) { - // If exactly one pointer went down, check for virtual key hit. - // Otherwise we will drop the entire stroke. - if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey) { - mCurrentVirtualKey.down = true; - mCurrentVirtualKey.downTime = when; - mCurrentVirtualKey.keyCode = virtualKey->keyCode; - mCurrentVirtualKey.scanCode = virtualKey->scanCode; - mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey( - when, getDevice(), virtualKey->keyCode, virtualKey->scanCode); - - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, - mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_DOWN, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - } - } - return true; - } - } - - // Disable all virtual key touches that happen within a short time interval of the - // most recent touch within the screen area. The idea is to filter out stray - // virtual key presses when interacting with the touch screen. - // - // Problems we're trying to solve: - // - // 1. While scrolling a list or dragging the window shade, the user swipes down into a - // virtual key area that is implemented by a separate touch panel and accidentally - // triggers a virtual key. - // - // 2. While typing in the on screen keyboard, the user taps slightly outside the screen - // area and accidentally triggers a virtual key. This often happens when virtual keys - // are layed out below the screen near to where the on screen keyboard's space bar - // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && - !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { - mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); - } - return false; -} - -void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags) { - int32_t keyCode = mCurrentVirtualKey.keyCode; - int32_t scanCode = mCurrentVirtualKey.scanCode; - nsecs_t downTime = mCurrentVirtualKey.downTime; - int32_t metaState = mContext->getGlobalMetaState(); - policyFlags |= POLICY_FLAG_VIRTUAL; - - NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, - mViewport.displayId, - policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); - getListener()->notifyKey(&args); -} - -void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; - if (!currentIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentCookedState.buttonState; - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mCurrentMotionAborted = true; - } -} - -void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentCookedState.buttonState; - - if (currentIdBits == lastIdBits) { - if (!currentIdBits.isEmpty()) { - // No pointer id changes so this is a move event. - // The listener takes care of batching moves so we don't have to deal with that here. - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } else { - // There may be pointers going up and pointers going down and pointers moving - // all at the same time. - BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); - BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); - BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); - BitSet32 dispatchedIdBits(lastIdBits.value); - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool moveNeeded = updateMovedPointers( - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mLastCookedState.cookedPointerData.pointerProperties, - mLastCookedState.cookedPointerData.pointerCoords, - mLastCookedState.cookedPointerData.idToIndex, - moveIdBits); - if (buttonState != mLastCookedState.buttonState) { - moveNeeded = true; - } - - // Dispatch pointer up events. - while (!upIdBits.isEmpty()) { - uint32_t upId = upIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mLastCookedState.cookedPointerData.pointerProperties, - mLastCookedState.cookedPointerData.pointerCoords, - mLastCookedState.cookedPointerData.idToIndex, - dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); - dispatchedIdBits.clearBit(upId); - } - - // Dispatch move events if any of the remaining pointers moved from their old locations. - // Although applications receive new locations as part of individual pointer up - // events, they do not generally handle them except when presented in a move event. - if (moveNeeded && !moveIdBits.isEmpty()) { - ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - - // Dispatch pointer down events using the new pointer locations. - while (!downIdBits.isEmpty()) { - uint32_t downId = downIdBits.clearFirstMarkedBit(); - dispatchedIdBits.markBit(downId); - - if (dispatchedIdBits.count() == 1) { - // First pointer is going down. Set down time. - mDownTime = when; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } -} - -void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { - if (mSentHoverEnter && - (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() - || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { - int32_t metaState = getContext()->getGlobalMetaState(); - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0, - mLastCookedState.deviceTimestamp, - mLastCookedState.cookedPointerData.pointerProperties, - mLastCookedState.cookedPointerData.pointerCoords, - mLastCookedState.cookedPointerData.idToIndex, - mLastCookedState.cookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = false; - } -} - -void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() - && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, - 0, 0, metaState, mCurrentRawState.buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = true; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, - mCurrentRawState.buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, - mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) { - BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState); - const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData); - const int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mLastCookedState.buttonState; - while (!releasedButtons.isEmpty()) { - int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit()); - buttonState &= ~actionButton; - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, - 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) { - BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState); - const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData); - const int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mLastCookedState.buttonState; - while (!pressedButtons.isEmpty()) { - int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit()); - buttonState |= actionButton; - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, - 0, metaState, buttonState, 0, - mCurrentCookedState.deviceTimestamp, - mCurrentCookedState.cookedPointerData.pointerProperties, - mCurrentCookedState.cookedPointerData.pointerCoords, - mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) { - if (!cookedPointerData.touchingIdBits.isEmpty()) { - return cookedPointerData.touchingIdBits; - } - return cookedPointerData.hoveringIdBits; -} - -void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; - - mCurrentCookedState.cookedPointerData.clear(); - mCurrentCookedState.deviceTimestamp = - mCurrentRawState.deviceTimestamp; - mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedState.cookedPointerData.hoveringIdBits = - mCurrentRawState.rawPointerData.hoveringIdBits; - mCurrentCookedState.cookedPointerData.touchingIdBits = - mCurrentRawState.rawPointerData.touchingIdBits; - - if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { - mCurrentCookedState.buttonState = 0; - } else { - mCurrentCookedState.buttonState = mCurrentRawState.buttonState; - } - - // Walk through the the active pointers and map device coordinates onto - // surface coordinates and adjust for display orientation. - for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; - - // Size - float touchMajor, touchMinor, toolMajor, toolMinor, size; - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - case Calibration::SIZE_CALIBRATION_DIAMETER: - case Calibration::SIZE_CALIBRATION_BOX: - case Calibration::SIZE_CALIBRATION_AREA: - if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { - touchMajor = in.touchMajor; - touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; - toolMajor = in.toolMajor; - toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.touchMinor.valid - ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; - } else if (mRawPointerAxes.touchMajor.valid) { - toolMajor = touchMajor = in.touchMajor; - toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid - ? in.touchMinor : in.touchMajor; - size = mRawPointerAxes.touchMinor.valid - ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; - } else if (mRawPointerAxes.toolMajor.valid) { - touchMajor = toolMajor = in.toolMajor; - touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid - ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.toolMinor.valid - ? avg(in.toolMajor, in.toolMinor) : in.toolMajor; - } else { - ALOG_ASSERT(false, "No touch or tool axes. " - "Size calibration should have been resolved to NONE."); - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - } - - if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = - mCurrentRawState.rawPointerData.touchingIdBits.count(); - if (touchingCount > 1) { - touchMajor /= touchingCount; - touchMinor /= touchingCount; - toolMajor /= touchingCount; - toolMinor /= touchingCount; - size /= touchingCount; - } - } - - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { - touchMajor *= mGeometricScale; - touchMinor *= mGeometricScale; - toolMajor *= mGeometricScale; - toolMinor *= mGeometricScale; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { - touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; - touchMinor = touchMajor; - toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; - toolMinor = toolMajor; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { - touchMinor = touchMajor; - toolMinor = toolMajor; - } - - mCalibration.applySizeScaleAndBias(&touchMajor); - mCalibration.applySizeScaleAndBias(&touchMinor); - mCalibration.applySizeScaleAndBias(&toolMajor); - mCalibration.applySizeScaleAndBias(&toolMinor); - size *= mSizeScale; - break; - default: - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - break; - } - - // Pressure - float pressure; - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - pressure = in.pressure * mPressureScale; - break; - default: - pressure = in.isHovering ? 0 : 1; - break; - } - - // Tilt and Orientation - float tilt; - float orientation; - if (mHaveTilt) { - float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; - float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; - orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); - tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); - } else { - tilt = 0; - - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - orientation = in.orientation * mOrientationScale; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: { - int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); - int32_t c2 = signExtendNybble(in.orientation & 0x0f); - if (c1 != 0 || c2 != 0) { - orientation = atan2f(c1, c2) * 0.5f; - float confidence = hypotf(c1, c2); - float scale = 1.0f + confidence / 16.0f; - touchMajor *= scale; - touchMinor /= scale; - toolMajor *= scale; - toolMinor /= scale; - } else { - orientation = 0; - } - break; - } - default: - orientation = 0; - } - } - - // Distance - float distance; - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_SCALED: - distance = in.distance * mDistanceScale; - break; - default: - distance = 0; - } - - // Coverage - int32_t rawLeft, rawTop, rawRight, rawBottom; - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_BOX: - rawLeft = (in.toolMinor & 0xffff0000) >> 16; - rawRight = in.toolMinor & 0x0000ffff; - rawBottom = in.toolMajor & 0x0000ffff; - rawTop = (in.toolMajor & 0xffff0000) >> 16; - break; - default: - rawLeft = rawTop = rawRight = rawBottom = 0; - break; - } - - // Adjust X,Y coords for device calibration - // TODO: Adjust coverage coords? - float xTransformed = in.x, yTransformed = in.y; - mAffineTransform.applyTo(xTransformed, yTransformed); - - // Adjust X, Y, and coverage coords for surface orientation. - float x, y; - float left, top, right, bottom; - - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate; - left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; - orientation -= M_PI_2; - if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { - orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - case DISPLAY_ORIENTATION_180: - x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale; - y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate; - left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; - right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; - bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; - orientation -= M_PI; - if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { - orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - case DISPLAY_ORIENTATION_270: - x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale; - y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; - right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; - bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - orientation += M_PI_2; - if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) { - orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); - } - break; - default: - x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - break; - } - - // Write output coords. - PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; - out.clear(); - out.setAxisValue(AMOTION_EVENT_AXIS_X, x); - out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); - out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); - out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); - out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); - } else { - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); - } - - // Write output properties. - PointerProperties& properties = - mCurrentCookedState.cookedPointerData.pointerProperties[i]; - uint32_t id = in.id; - properties.clear(); - properties.id = id; - properties.toolType = in.toolType; - - // Write id index. - mCurrentCookedState.cookedPointerData.idToIndex[id] = i; - } -} - -void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, - PointerUsage pointerUsage) { - if (pointerUsage != mPointerUsage) { - abortPointerUsage(when, policyFlags); - mPointerUsage = pointerUsage; - } - - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); - break; - case POINTER_USAGE_STYLUS: - dispatchPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - dispatchPointerMouse(when, policyFlags); - break; - default: - break; - } -} - -void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - abortPointerGestures(when, policyFlags); - break; - case POINTER_USAGE_STYLUS: - abortPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - abortPointerMouse(when, policyFlags); - break; - default: - break; - } - - mPointerUsage = POINTER_USAGE_NONE; -} - -void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, - bool isTimeout) { - // Update current gesture coordinates. - bool cancelPreviousGesture, finishPreviousGesture; - bool sendEvents = preparePointerGestures(when, - &cancelPreviousGesture, &finishPreviousGesture, isTimeout); - if (!sendEvents) { - return; - } - if (finishPreviousGesture) { - cancelPreviousGesture = false; - } - - // Update the pointer presentation and spots. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - if (finishPreviousGesture || cancelPreviousGesture) { - mPointerController->clearSpots(); - } - - if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { - mPointerController->setSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, - mPointerController->getDisplayId()); - } - } else { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - } - - // Show or hide the pointer if needed. - switch (mPointerGesture.currentGestureMode) { - case PointerGesture::NEUTRAL: - case PointerGesture::QUIET: - if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH - && mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) { - // Remind the user of where the pointer is after finishing a gesture with spots. - mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); - } - break; - case PointerGesture::TAP: - case PointerGesture::TAP_DRAG: - case PointerGesture::BUTTON_CLICK_OR_DRAG: - case PointerGesture::HOVER: - case PointerGesture::PRESS: - case PointerGesture::SWIPE: - // Unfade the pointer when the current gesture manipulates the - // area directly under the pointer. - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - break; - case PointerGesture::FREEFORM: - // Fade the pointer when the current gesture manipulates a different - // area and there are spots to guide the user experience. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } else { - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - break; - } - - // Send events! - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentCookedState.buttonState; - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP - || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG - || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - || mPointerGesture.currentGestureMode == PointerGesture::PRESS - || mPointerGesture.currentGestureMode == PointerGesture::SWIPE - || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; - bool moveNeeded = false; - if (down && !cancelPreviousGesture && !finishPreviousGesture - && !mPointerGesture.lastGestureIdBits.isEmpty() - && !mPointerGesture.currentGestureIdBits.isEmpty()) { - BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value - & mPointerGesture.lastGestureIdBits.value); - moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - movedGestureIdBits); - if (buttonState != mLastCookedState.buttonState) { - moveNeeded = true; - } - } - - // Send motion events for all pointers that went up or were canceled. - BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); - if (!dispatchedGestureIdBits.isEmpty()) { - if (cancelPreviousGesture) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, -1, 0, - 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clear(); - } else { - BitSet32 upGestureIdBits; - if (finishPreviousGesture) { - upGestureIdBits = dispatchedGestureIdBits; - } else { - upGestureIdBits.value = dispatchedGestureIdBits.value - & ~mPointerGesture.currentGestureIdBits.value; - } - while (!upGestureIdBits.isEmpty()) { - uint32_t id = upGestureIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, id, - 0, 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clearBit(id); - } - } - } - - // Send motion events for all pointers that moved. - if (moveNeeded) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Send motion events for all pointers that went down. - if (down) { - BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value - & ~dispatchedGestureIdBits.value); - while (!downGestureIdBits.isEmpty()) { - uint32_t id = downGestureIdBits.clearFirstMarkedBit(); - dispatchedGestureIdBits.markBit(id); - - if (dispatchedGestureIdBits.count() == 1) { - mPointerGesture.downTime = when; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, - /* deviceTimestamp */ 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, id, - 0, 0, mPointerGesture.downTime); - } - } - - // Send motion events for hover. - if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } else if (dispatchedGestureIdBits.isEmpty() - && !mPointerGesture.lastGestureIdBits.isEmpty()) { - // Synthesize a hover move event after all pointers go up to indicate that - // the pointer is hovering again even if the user is not currently touching - // the touch pad. This ensures that a view will receive a fresh hover enter - // event after a tap. - float x, y; - mPointerController->getPosition(&x, &y); - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - - PointerCoords pointerCoords; - pointerCoords.clear(); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - - const int32_t displayId = mPointerController->getDisplayId(); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - 0, 0, mPointerGesture.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - // Update state. - mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; - if (!down) { - mPointerGesture.lastGestureIdBits.clear(); - } else { - mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; - for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - mPointerGesture.lastGestureProperties[index].copyFrom( - mPointerGesture.currentGestureProperties[index]); - mPointerGesture.lastGestureCoords[index].copyFrom( - mPointerGesture.currentGestureCoords[index]); - mPointerGesture.lastGestureIdToIndex[id] = index; - } - } -} - -void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { - // Cancel previously dispatches pointers. - if (!mPointerGesture.lastGestureIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentRawState.buttonState; - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - mPointerGesture.lastGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Reset the current pointer gesture. - mPointerGesture.reset(); - mPointerVelocityControl.reset(); - - // Remove any current spots. - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } -} - -bool TouchInputMapper::preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) { - *outCancelPreviousGesture = false; - *outFinishPreviousGesture = false; - - // Handle TAP timeout. - if (isTimeout) { -#if DEBUG_GESTURES - ALOGD("Gestures: Processing timeout"); -#endif - - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - // The tap/drag timeout has not yet expired. - getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime - + mConfig.pointerGestureTapDragInterval); - } else { - // The tap is finished. -#if DEBUG_GESTURES - ALOGD("Gestures: TAP finished"); -#endif - *outFinishPreviousGesture = true; - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - return true; - } - } - - // We did not handle this timeout. - return false; - } - - const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); - const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); - - // Update the velocity tracker. - { - VelocityTracker::Position positions[MAX_POINTERS]; - uint32_t count = 0; - for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(id); - positions[count].x = pointer.x * mPointerXMovementScale; - positions[count].y = pointer.y * mPointerYMovementScale; - } - mPointerGesture.velocityTracker.addMovement(when, - mCurrentCookedState.fingerIdBits, positions); - } - - // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning - // to NEUTRAL, then we should not generate tap event. - if (mPointerGesture.lastGestureMode != PointerGesture::HOVER - && mPointerGesture.lastGestureMode != PointerGesture::TAP - && mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) { - mPointerGesture.resetTap(); - } - - // Pick a new active touch id if needed. - // Choose an arbitrary pointer that just went down, if there is one. - // Otherwise choose an arbitrary remaining pointer. - // This guarantees we always have an active touch id when there is at least one pointer. - // We keep the same active touch id for as long as possible. - int32_t lastActiveTouchId = mPointerGesture.activeTouchId; - int32_t activeTouchId = lastActiveTouchId; - if (activeTouchId < 0) { - if (!mCurrentCookedState.fingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentCookedState.fingerIdBits.firstMarkedBit(); - mPointerGesture.firstTouchTime = when; - } - } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { - if (!mCurrentCookedState.fingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentCookedState.fingerIdBits.firstMarkedBit(); - } else { - activeTouchId = mPointerGesture.activeTouchId = -1; - } - } - - // Determine whether we are in quiet time. - bool isQuietTime = false; - if (activeTouchId < 0) { - mPointerGesture.resetQuietTime(); - } else { - isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; - if (!isQuietTime) { - if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS - || mPointerGesture.lastGestureMode == PointerGesture::SWIPE - || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) - && currentFingerCount < 2) { - // Enter quiet time when exiting swipe or freeform state. - // This is to prevent accidentally entering the hover state and flinging the - // pointer when finishing a swipe and there is still one pointer left onscreen. - isQuietTime = true; - } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - && currentFingerCount >= 2 - && !isPointerDown(mCurrentRawState.buttonState)) { - // Enter quiet time when releasing the button and there are still two or more - // fingers down. This may indicate that one finger was used to press the button - // but it has not gone up yet. - isQuietTime = true; - } - if (isQuietTime) { - mPointerGesture.quietTime = when; - } - } - } - - // Switch states based on button and pointer state. - if (isQuietTime) { - // Case 1: Quiet time. (QUIET) -#if DEBUG_GESTURES - ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime - + mConfig.pointerGestureQuietInterval - when) * 0.000001f); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { - *outFinishPreviousGesture = true; - } - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::QUIET; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentRawState.buttonState)) { - // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) - // The pointer follows the active touch point. - // Emit DOWN, MOVE, UP events at the pointer location. - // - // Only the active touch matters; other fingers are ignored. This policy helps - // to handle the case where the user places a second finger on the touch pad - // to apply the necessary force to depress an integrated button below the surface. - // We don't want the second finger to be delivered to applications. - // - // For this to work well, we need to make sure to track the pointer that is really - // active. If the user first puts one finger down to click then adds another - // finger to drag then the active pointer should switch to the finger that is - // being dragged. -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " - "currentFingerCount=%d", activeTouchId, currentFingerCount); -#endif - // Reset state when just starting. - if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { - *outFinishPreviousGesture = true; - mPointerGesture.activeGestureId = 0; - } - - // Switch pointers if needed. - // Find the fastest pointer and follow it. - if (activeTouchId >= 0 && currentFingerCount > 1) { - int32_t bestId = -1; - float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - float vx, vy; - if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { - float speed = hypotf(vx, vy); - if (speed > bestSpeed) { - bestId = id; - bestSpeed = speed; - } - } - } - if (bestId >= 0 && bestId != activeTouchId) { - mPointerGesture.activeTouchId = activeTouchId = bestId; -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " - "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); -#endif - } - } - - float deltaX = 0, deltaY = 0; - if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawState.rawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawState.rawPointerData.pointerForId(activeTouchId); - deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the click will occur at the position of the anchor - // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (currentFingerCount == 0) { - // Case 3. No fingers down and button is not pressed. (NEUTRAL) - if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { - *outFinishPreviousGesture = true; - } - - // Watch for taps coming out of HOVER or TAP_DRAG mode. - // Checking for taps after TAP_DRAG allows us to detect double-taps. - bool tapped = false; - if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER - || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) - && lastFingerCount == 1) { - if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop - && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP"); -#endif - - mPointerGesture.tapUpTime = when; - getContext()->requestTimeoutAtTime(when - + mConfig.pointerGestureTapDragInterval); - - mPointerGesture.activeGestureId = 0; - mPointerGesture.currentGestureMode = PointerGesture::TAP; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit( - mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[ - mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = - mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - - tapped = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - if (mPointerGesture.tapDownTime != LLONG_MIN) { - ALOGD("Gestures: Not a TAP, %0.3fms since down", - (when - mPointerGesture.tapDownTime) * 0.000001f); - } else { - ALOGD("Gestures: Not a TAP, incompatible mode transitions"); - } -#endif - } - } - - mPointerVelocityControl.reset(); - - if (!tapped) { -#if DEBUG_GESTURES - ALOGD("Gestures: NEUTRAL"); -#endif - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - } - } else if (currentFingerCount == 1) { - // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) - // The pointer follows the active touch point. - // When in HOVER, emit HOVER_MOVE events at the pointer location. - // When in TAP_DRAG, emit MOVE events at the pointer location. - ALOG_ASSERT(activeTouchId >= 0); - - mPointerGesture.currentGestureMode = PointerGesture::HOVER; - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop - && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", - (when - mPointerGesture.tapUpTime) * 0.000001f); -#endif - } - } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } - - float deltaX = 0, deltaY = 0; - if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawState.rawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawState.rawPointerData.pointerForId(activeTouchId); - deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the hover or drag will occur at the position of the anchor spot. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - bool down; - if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP_DRAG"); -#endif - down = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: HOVER"); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { - *outFinishPreviousGesture = true; - } - mPointerGesture.activeGestureId = 0; - down = false; - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - down ? 1.0f : 0.0f); - - if (lastFingerCount == 0 && currentFingerCount != 0) { - mPointerGesture.resetTap(); - mPointerGesture.tapDownTime = when; - mPointerGesture.tapX = x; - mPointerGesture.tapY = y; - } - } else { - // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) - // We need to provide feedback for each finger that goes down so we cannot wait - // for the fingers to move before deciding what to do. - // - // The ambiguous case is deciding what to do when there are two fingers down but they - // have not moved enough to determine whether they are part of a drag or part of a - // freeform gesture, or just a press or long-press at the pointer location. - // - // When there are two fingers we start with the PRESS hypothesis and we generate a - // down at the pointer location. - // - // When the two fingers move enough or when additional fingers are added, we make - // a decision to transition into SWIPE or FREEFORM mode accordingly. - ALOG_ASSERT(activeTouchId >= 0); - - bool settled = when >= mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval; - if (mPointerGesture.lastGestureMode != PointerGesture::PRESS - && mPointerGesture.lastGestureMode != PointerGesture::SWIPE - && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - *outFinishPreviousGesture = true; - } else if (!settled && currentFingerCount > lastFingerCount) { - // Additional pointers have gone down but not yet settled. - // Reset the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " - "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval - when) - * 0.000001f); -#endif - *outCancelPreviousGesture = true; - } else { - // Continue previous gesture. - mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; - } - - if (*outFinishPreviousGesture || *outCancelPreviousGesture) { - mPointerGesture.currentGestureMode = PointerGesture::PRESS; - mPointerGesture.activeGestureId = 0; - mPointerGesture.referenceIdBits.clear(); - mPointerVelocityControl.reset(); - - // Use the centroid and pointer location as the reference points for the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " - "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval - when) - * 0.000001f); -#endif - mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers( - &mPointerGesture.referenceTouchX, - &mPointerGesture.referenceTouchY); - mPointerController->getPosition(&mPointerGesture.referenceGestureX, - &mPointerGesture.referenceGestureY); - } - - // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value - & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - mPointerGesture.referenceDeltas[id].dx = 0; - mPointerGesture.referenceDeltas[id].dy = 0; - } - mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; - - // Add delta for all fingers and calculate a common movement delta. - float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value - & mCurrentCookedState.fingerIdBits.value); - for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { - bool first = (idBits == commonIdBits); - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx += cpd.x - lpd.x; - delta.dy += cpd.y - lpd.y; - - if (first) { - commonDeltaX = delta.dx; - commonDeltaY = delta.dy; - } else { - commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); - commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); - } - } - - // Consider transitions from PRESS to SWIPE or MULTITOUCH. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { - float dist[MAX_POINTER_ID + 1]; - int32_t distOverThreshold = 0; - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - dist[id] = hypotf(delta.dx * mPointerXZoomScale, - delta.dy * mPointerYZoomScale); - if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { - distOverThreshold += 1; - } - } - - // Only transition when at least two pointers have moved further than - // the minimum distance threshold. - if (distOverThreshold >= 2) { - if (currentFingerCount > 2) { - // There are more than two pointers, switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are exactly two pointers. - BitSet32 idBits(mCurrentCookedState.fingerIdBits); - uint32_t id1 = idBits.clearFirstMarkedBit(); - uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = - mCurrentRawState.rawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = - mCurrentRawState.rawPointerData.pointerForId(id2); - float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); - if (mutualDistance > mPointerGestureMaxSwipeWidth) { - // There are two pointers but they are too far apart for a SWIPE, - // switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", - mutualDistance, mPointerGestureMaxSwipeWidth); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are two pointers. Wait for both pointers to start moving - // before deciding whether this is a SWIPE or FREEFORM gesture. - float dist1 = dist[id1]; - float dist2 = dist[id2]; - if (dist1 >= mConfig.pointerGestureMultitouchMinDistance - && dist2 >= mConfig.pointerGestureMultitouchMinDistance) { - // Calculate the dot product of the displacement vectors. - // When the vectors are oriented in approximately the same direction, - // the angle betweeen them is near zero and the cosine of the angle - // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). - PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; - PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; - float dx1 = delta1.dx * mPointerXZoomScale; - float dy1 = delta1.dy * mPointerYZoomScale; - float dx2 = delta2.dx * mPointerXZoomScale; - float dy2 = delta2.dy * mPointerYZoomScale; - float dot = dx1 * dx2 + dy1 * dy2; - float cosine = dot / (dist1 * dist2); // denominator always > 0 - if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { - // Pointers are moving in the same direction. Switch to SWIPE. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to SWIPE, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f >= %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, - dist2, mConfig.pointerGestureMultitouchMinDistance, - cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - mPointerGesture.currentGestureMode = PointerGesture::SWIPE; - } else { - // Pointers are moving in different directions. Switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f < %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, - dist2, mConfig.pointerGestureMultitouchMinDistance, - cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - } - } - } - } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // Switch from SWIPE to FREEFORM if additional pointers go down. - // Cancel previous gesture. - if (currentFingerCount > 2) { -#if DEBUG_GESTURES - ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - - // Move the reference points based on the overall group motion of the fingers - // except in PRESS mode while waiting for a transition to occur. - if (mPointerGesture.currentGestureMode != PointerGesture::PRESS - && (commonDeltaX || commonDeltaY)) { - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx = 0; - delta.dy = 0; - } - - mPointerGesture.referenceTouchX += commonDeltaX; - mPointerGesture.referenceTouchY += commonDeltaY; - - commonDeltaX *= mPointerXMovementScale; - commonDeltaY *= mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); - mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); - - mPointerGesture.referenceGestureX += commonDeltaX; - mPointerGesture.referenceGestureY += commonDeltaY; - } - - // Report gestures. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS - || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // PRESS or SWIPE mode. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, - mPointerGesture.referenceGestureX); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, - mPointerGesture.referenceGestureY); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { - // FREEFORM mode. -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - - BitSet32 mappedTouchIdBits; - BitSet32 usedGestureIdBits; - if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - // Initially, assign the active gesture id to the active touch point - // if there is one. No other touch id bits are mapped yet. - if (!*outCancelPreviousGesture) { - mappedTouchIdBits.markBit(activeTouchId); - usedGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = - mPointerGesture.activeGestureId; - } else { - mPointerGesture.activeGestureId = -1; - } - } else { - // Otherwise, assume we mapped all touches from the previous frame. - // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value - & mCurrentCookedState.fingerIdBits.value; - usedGestureIdBits = mPointerGesture.lastGestureIdBits; - - // Check whether we need to choose a new active gesture id because the - // current went went up. - for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value - & ~mCurrentCookedState.fingerIdBits.value); - !upTouchIdBits.isEmpty(); ) { - uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); - uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; - if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { - mPointerGesture.activeGestureId = -1; - break; - } - } - } - -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM follow up " - "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " - "activeGestureId=%d", - mappedTouchIdBits.value, usedGestureIdBits.value, - mPointerGesture.activeGestureId); -#endif - - BitSet32 idBits(mCurrentCookedState.fingerIdBits); - for (uint32_t i = 0; i < currentFingerCount; i++) { - uint32_t touchId = idBits.clearFirstMarkedBit(); - uint32_t gestureId; - if (!mappedTouchIdBits.hasBit(touchId)) { - gestureId = usedGestureIdBits.markFirstUnmarkedBit(); - mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "new mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } else { - gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "existing mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } - mPointerGesture.currentGestureIdBits.markBit(gestureId); - mPointerGesture.currentGestureIdToIndex[gestureId] = i; - - const RawPointerData::Pointer& pointer = - mCurrentRawState.rawPointerData.pointerForId(touchId); - float deltaX = (pointer.x - mPointerGesture.referenceTouchX) - * mPointerXZoomScale; - float deltaY = (pointer.y - mPointerGesture.referenceTouchY) - * mPointerYZoomScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - - mPointerGesture.currentGestureProperties[i].clear(); - mPointerGesture.currentGestureProperties[i].id = gestureId; - mPointerGesture.currentGestureProperties[i].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[i].clear(); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } - - if (mPointerGesture.activeGestureId < 0) { - mPointerGesture.activeGestureId = - mPointerGesture.currentGestureIdBits.firstMarkedBit(); -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM new " - "activeGestureId=%d", mPointerGesture.activeGestureId); -#endif - } - } - } - - mPointerController->setButtonState(mCurrentRawState.buttonState); - -#if DEBUG_GESTURES - ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " - "currentGestureMode=%d, currentGestureIdBits=0x%08x, " - "lastGestureMode=%d, lastGestureIdBits=0x%08x", - toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), - mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value, - mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value); - for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; - ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, - coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } - for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; - ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, - coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - return true; -} - -void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentCookedState.stylusIdBits.isEmpty()) { - uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; - float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); - mPointerController->setPosition(x, y); - - hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); - down = !hovering; - - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedState.cookedPointerData.pointerCoords[index]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; - } else { - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); -} - -void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentCookedState.mouseIdBits.isEmpty()) { - uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; - float deltaX = 0, deltaY = 0; - if (mLastCookedState.mouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; - deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x - - mLastRawState.rawPointerData.pointers[lastIndex].x) - * mPointerXMovementScale; - deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y - - mLastRawState.rawPointerData.pointers[lastIndex].y) - * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - down = isPointerDown(mCurrentRawState.buttonState); - hovering = !down; - - float x, y; - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - hovering ? 0.0f : 1.0f); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; - } else { - mPointerVelocityControl.reset(); - - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); - - mPointerVelocityControl.reset(); -} - -void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, - bool down, bool hovering) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t displayId = mViewport.displayId; - - if (mPointerController != nullptr) { - if (down || hovering) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentRawState.buttonState); - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } - displayId = mPointerController->getDisplayId(); - } - - if (mPointerSimple.down && !down) { - mPointerSimple.down = false; - - // Send up. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - if (mPointerSimple.hovering && !hovering) { - mPointerSimple.hovering = false; - - // Send hover exit. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - if (down) { - if (!mPointerSimple.down) { - mPointerSimple.down = true; - mPointerSimple.downTime = when; - - // Send down. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - // Send move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - if (hovering) { - if (!mPointerSimple.hovering) { - mPointerSimple.hovering = true; - - // Send hover enter. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, - mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - // Send hover move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, - mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { - float vscroll = mCurrentRawState.rawVScroll; - float hscroll = mCurrentRawState.rawHScroll; - mWheelYVelocityControl.move(when, nullptr, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, nullptr); - - // Send scroll. - PointerCoords pointerCoords; - pointerCoords.copyFrom(mPointerSimple.currentCoords); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); - getListener()->notifyMotion(&args); - } - - // Save state. - if (down || hovering) { - mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); - mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); - } else { - mPointerSimple.reset(); - } -} - -void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - dispatchPointerSimple(when, policyFlags, false, false); -} - -void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t actionButton, int32_t flags, - int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, - float xPrecision, float yPrecision, nsecs_t downTime) { - PointerCoords pointerCoords[MAX_POINTERS]; - PointerProperties pointerProperties[MAX_POINTERS]; - uint32_t pointerCount = 0; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = idToIndex[id]; - pointerProperties[pointerCount].copyFrom(properties[index]); - pointerCoords[pointerCount].copyFrom(coords[index]); - - if (changedId >= 0 && id == uint32_t(changedId)) { - action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } - - pointerCount += 1; - } - - ALOG_ASSERT(pointerCount != 0); - - if (changedId >= 0 && pointerCount == 1) { - // Replace initial down and final up action. - // We can compare the action without masking off the changed pointer index - // because we know the index is 0. - if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { - action = AMOTION_EVENT_ACTION_DOWN; - } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { - action = AMOTION_EVENT_ACTION_UP; - } else { - // Can't happen. - ALOG_ASSERT(false); - } - } - const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE); - const int32_t deviceId = getDeviceId(); - std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId); - std::for_each(frames.begin(), frames.end(), - [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, - source, displayId, policyFlags, - action, actionButton, flags, metaState, buttonState, MotionClassification::NONE, - edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords, - xPrecision, yPrecision, downTime, std::move(frames)); - getListener()->notifyMotion(&args); -} - -bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex, - BitSet32 idBits) const { - bool changed = false; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t inIndex = inIdToIndex[id]; - uint32_t outIndex = outIdToIndex[id]; - - const PointerProperties& curInProperties = inProperties[inIndex]; - const PointerCoords& curInCoords = inCoords[inIndex]; - PointerProperties& curOutProperties = outProperties[outIndex]; - PointerCoords& curOutCoords = outCoords[outIndex]; - - if (curInProperties != curOutProperties) { - curOutProperties.copyFrom(curInProperties); - changed = true; - } - - if (curInCoords != curOutCoords) { - curOutCoords.copyFrom(curInCoords); - changed = true; - } - } - return changed; -} - -void TouchInputMapper::fadePointer() { - if (mPointerController != nullptr) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - -void TouchInputMapper::cancelTouch(nsecs_t when) { - abortPointerUsage(when, 0 /*policyFlags*/); - abortTouches(when, 0 /* policyFlags*/); -} - -bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { - const float scaledX = x * mXScale; - const float scaledY = y * mYScale; - return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue - && scaledX >= mPhysicalLeft && scaledX <= mPhysicalLeft + mPhysicalWidth - && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue - && scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight; -} - -const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) { - - for (const VirtualKey& virtualKey: mVirtualKeys) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " - "left=%d, top=%d, right=%d, bottom=%d", - x, y, - virtualKey.keyCode, virtualKey.scanCode, - virtualKey.hitLeft, virtualKey.hitTop, - virtualKey.hitRight, virtualKey.hitBottom); -#endif - - if (virtualKey.isHit(x, y)) { - return & virtualKey; - } - } - - return nullptr; -} - -void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { - uint32_t currentPointerCount = current->rawPointerData.pointerCount; - uint32_t lastPointerCount = last->rawPointerData.pointerCount; - - current->rawPointerData.clearIdBits(); - - if (currentPointerCount == 0) { - // No pointers to assign. - return; - } - - if (lastPointerCount == 0) { - // All pointers are new. - for (uint32_t i = 0; i < currentPointerCount; i++) { - uint32_t id = i; - current->rawPointerData.pointers[i].id = id; - current->rawPointerData.idToIndex[id] = i; - current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); - } - return; - } - - if (currentPointerCount == 1 && lastPointerCount == 1 - && current->rawPointerData.pointers[0].toolType - == last->rawPointerData.pointers[0].toolType) { - // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = last->rawPointerData.pointers[0].id; - current->rawPointerData.pointers[0].id = id; - current->rawPointerData.idToIndex[id] = 0; - current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); - return; - } - - // General case. - // We build a heap of squared euclidean distances between current and last pointers - // associated with the current and last pointer indices. Then, we find the best - // match (by distance) for each current pointer. - // The pointers must have the same tool type but it is possible for them to - // transition from hovering to touching or vice-versa while retaining the same id. - PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; - - uint32_t heapSize = 0; - for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; - currentPointerIndex++) { - for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; - lastPointerIndex++) { - const RawPointerData::Pointer& currentPointer = - current->rawPointerData.pointers[currentPointerIndex]; - const RawPointerData::Pointer& lastPointer = - last->rawPointerData.pointers[lastPointerIndex]; - if (currentPointer.toolType == lastPointer.toolType) { - int64_t deltaX = currentPointer.x - lastPointer.x; - int64_t deltaY = currentPointer.y - lastPointer.y; - - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - - // Insert new element into the heap (sift up). - heap[heapSize].currentPointerIndex = currentPointerIndex; - heap[heapSize].lastPointerIndex = lastPointerIndex; - heap[heapSize].distance = distance; - heapSize += 1; - } - } - } - - // Heapify - for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { - startIndex -= 1; - for (uint32_t parentIndex = startIndex; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - - // Pull matches out by increasing order of distance. - // To avoid reassigning pointers that have already been matched, the loop keeps track - // of which last and current pointers have been matched using the matchedXXXBits variables. - // It also tracks the used pointer id bits. - BitSet32 matchedLastBits(0); - BitSet32 matchedCurrentBits(0); - BitSet32 usedIdBits(0); - bool first = true; - for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { - while (heapSize > 0) { - if (first) { - // The first time through the loop, we just consume the root element of - // the heap (the one with smallest distance). - first = false; - } else { - // Previous iterations consumed the root element of the heap. - // Pop root element off of the heap (sift down). - heap[0] = heap[heapSize]; - for (uint32_t parentIndex = 0; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - } - - heapSize -= 1; - - uint32_t currentPointerIndex = heap[0].currentPointerIndex; - if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched - - uint32_t lastPointerIndex = heap[0].lastPointerIndex; - if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched - - matchedCurrentBits.markBit(currentPointerIndex); - matchedLastBits.markBit(lastPointerIndex); - - uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; - current->rawPointerData.pointers[currentPointerIndex].id = id; - current->rawPointerData.idToIndex[id] = currentPointerIndex; - current->rawPointerData.markIdBit(id, - current->rawPointerData.isHovering(currentPointerIndex)); - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 - ", id=%" PRIu32 ", distance=%" PRIu64, - lastPointerIndex, currentPointerIndex, id, heap[0].distance); -#endif - break; - } - } - - // Assign fresh ids to pointers that were not matched in the process. - for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { - uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); - uint32_t id = usedIdBits.markFirstUnmarkedBit(); - - current->rawPointerData.pointers[currentPointerIndex].id = id; - current->rawPointerData.idToIndex[id] = currentPointerIndex; - current->rawPointerData.markIdBit(id, - current->rawPointerData.isHovering(currentPointerIndex)); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id); -#endif - } -} - -int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { - return AKEY_STATE_VIRTUAL; - } - - for (const VirtualKey& virtualKey : mVirtualKeys) { - if (virtualKey.keyCode == keyCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { - return AKEY_STATE_VIRTUAL; - } - - for (const VirtualKey& virtualKey : mVirtualKeys) { - if (virtualKey.scanCode == scanCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - for (const VirtualKey& virtualKey : mVirtualKeys) { - for (size_t i = 0; i < numCodes; i++) { - if (virtualKey.keyCode == keyCodes[i]) { - outFlags[i] = 1; - } - } - } - - return true; -} - -std::optional<int32_t> TouchInputMapper::getAssociatedDisplay() { - if (mParameters.hasAssociatedDisplay) { - if (mDeviceMode == DEVICE_MODE_POINTER) { - return std::make_optional(mPointerController->getDisplayId()); - } else { - return std::make_optional(mViewport.displayId); - } - } - return std::nullopt; -} - -// --- SingleTouchInputMapper --- - -SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { -} - -SingleTouchInputMapper::~SingleTouchInputMapper() { -} - -void SingleTouchInputMapper::reset(nsecs_t when) { - mSingleTouchMotionAccumulator.reset(getDevice()); - - TouchInputMapper::reset(when); -} - -void SingleTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mSingleTouchMotionAccumulator.process(rawEvent); -} - -void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { - if (mTouchButtonAccumulator.isToolActive()) { - outState->rawPointerData.pointerCount = 1; - outState->rawPointerData.idToIndex[0] = 0; - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE - && (mTouchButtonAccumulator.isHovering() - || (mRawPointerAxes.pressure.valid - && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - outState->rawPointerData.markIdBit(0, isHovering); - - RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; - outPointer.id = 0; - outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); - outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); - outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); - outPointer.touchMajor = 0; - outPointer.touchMinor = 0; - outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.orientation = 0; - outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); - outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); - outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - outPointer.isHovering = isHovering; - } -} - -void SingleTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); - getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); -} - -bool SingleTouchInputMapper::hasStylus() const { - return mTouchButtonAccumulator.hasStylus(); -} - - -// --- MultiTouchInputMapper --- - -MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { -} - -MultiTouchInputMapper::~MultiTouchInputMapper() { -} - -void MultiTouchInputMapper::reset(nsecs_t when) { - mMultiTouchMotionAccumulator.reset(getDevice()); - - mPointerIdBits.clear(); - - TouchInputMapper::reset(when); -} - -void MultiTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mMultiTouchMotionAccumulator.process(rawEvent); -} - -void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { - size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); - size_t outCount = 0; - BitSet32 newPointerIdBits; - mHavePointerIds = true; - - for (size_t inIndex = 0; inIndex < inCount; inIndex++) { - const MultiTouchMotionAccumulator::Slot* inSlot = - mMultiTouchMotionAccumulator.getSlot(inIndex); - if (!inSlot->isInUse()) { - continue; - } - - if (outCount >= MAX_POINTERS) { -#if DEBUG_POINTERS - ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " - "ignoring the rest.", - getDeviceName().c_str(), MAX_POINTERS); -#endif - break; // too many fingers! - } - - RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; - outPointer.x = inSlot->getX(); - outPointer.y = inSlot->getY(); - outPointer.pressure = inSlot->getPressure(); - outPointer.touchMajor = inSlot->getTouchMajor(); - outPointer.touchMinor = inSlot->getTouchMinor(); - outPointer.toolMajor = inSlot->getToolMajor(); - outPointer.toolMinor = inSlot->getToolMinor(); - outPointer.orientation = inSlot->getOrientation(); - outPointer.distance = inSlot->getDistance(); - outPointer.tiltX = 0; - outPointer.tiltY = 0; - - outPointer.toolType = inSlot->getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - } - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE - && (mTouchButtonAccumulator.isHovering() - || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); - outPointer.isHovering = isHovering; - - // Assign pointer id using tracking id if available. - if (mHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); - int32_t id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; - } - } - if (id < 0) { - mHavePointerIds = false; - outState->rawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - outState->rawPointerData.idToIndex[id] = outCount; - outState->rawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); - } - } - outCount += 1; - } - - outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp(); - outState->rawPointerData.pointerCount = outCount; - mPointerIdBits = newPointerIdBits; - - mMultiTouchMotionAccumulator.finishSync(); -} - -void MultiTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); - getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); - getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); - getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); - - if (mRawPointerAxes.trackingId.valid - && mRawPointerAxes.slot.valid - && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { - size_t slotCount = mRawPointerAxes.slot.maxValue + 1; - if (slotCount > MAX_SLOTS) { - ALOGW("MultiTouch Device %s reported %zu slots but the framework " - "only supports a maximum of %zu slots at this time.", - getDeviceName().c_str(), slotCount, MAX_SLOTS); - slotCount = MAX_SLOTS; - } - mMultiTouchMotionAccumulator.configure(getDevice(), - slotCount, true /*usingSlotsProtocol*/); - } else { - mMultiTouchMotionAccumulator.configure(getDevice(), - MAX_POINTERS, false /*usingSlotsProtocol*/); - } -} - -bool MultiTouchInputMapper::hasStylus() const { - return mMultiTouchMotionAccumulator.hasStylus() - || mTouchButtonAccumulator.hasStylus(); -} - -// --- ExternalStylusInputMapper - -ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : - InputMapper(device) { - -} - -uint32_t ExternalStylusInputMapper::getSources() { - return AINPUT_SOURCE_STYLUS; -} - -void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, - 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); -} - -void ExternalStylusInputMapper::dump(std::string& dump) { - dump += INDENT2 "External Stylus Input Mapper:\n"; - dump += INDENT3 "Raw Stylus Axes:\n"; - dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); - dump += INDENT3 "Stylus State:\n"; - dumpStylusState(dump, mStylusState); -} - -void ExternalStylusInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); - mTouchButtonAccumulator.configure(getDevice()); -} - -void ExternalStylusInputMapper::reset(nsecs_t when) { - InputDevice* device = getDevice(); - mSingleTouchMotionAccumulator.reset(device); - mTouchButtonAccumulator.reset(device); - InputMapper::reset(when); -} - -void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { - mSingleTouchMotionAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void ExternalStylusInputMapper::sync(nsecs_t when) { - mStylusState.clear(); - - mStylusState.when = when; - - mStylusState.toolType = mTouchButtonAccumulator.getToolType(); - if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - - int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); - if (mRawPressureAxis.valid) { - mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; - } else if (mTouchButtonAccumulator.isToolActive()) { - mStylusState.pressure = 1.0f; - } else { - mStylusState.pressure = 0.0f; - } - - mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); - - mContext->dispatchExternalStylusState(mStylusState); -} - - -// --- JoystickInputMapper --- - -JoystickInputMapper::JoystickInputMapper(InputDevice* device) : - InputMapper(device) { -} - -JoystickInputMapper::~JoystickInputMapper() { -} - -uint32_t JoystickInputMapper::getSources() { - return AINPUT_SOURCE_JOYSTICK; -} - -void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - for (size_t i = 0; i < mAxes.size(); i++) { - const Axis& axis = mAxes.valueAt(i); - addMotionRange(axis.axisInfo.axis, axis, info); - - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - addMotionRange(axis.axisInfo.highAxis, axis, info); - - } - } -} - -void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, - InputDeviceInfo* info) { - info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to register - * the old axes as duplicates of their corresponding new ones. */ - int32_t compatAxis = getCompatAxis(axisId); - if (compatAxis >= 0) { - info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - } -} - -/* A mapping from axes the joystick actually has to the axes that should be - * artificially created for compatibility purposes. - * Returns -1 if no compatibility axis is needed. */ -int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { - switch(axis) { - case AMOTION_EVENT_AXIS_LTRIGGER: - return AMOTION_EVENT_AXIS_BRAKE; - case AMOTION_EVENT_AXIS_RTRIGGER: - return AMOTION_EVENT_AXIS_GAS; - } - return -1; -} - -void JoystickInputMapper::dump(std::string& dump) { - dump += INDENT2 "Joystick Input Mapper:\n"; - - dump += INDENT3 "Axes:\n"; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - const char* label = getAxisLabel(axis.axisInfo.axis); - if (label) { - dump += StringPrintf(INDENT4 "%s", label); - } else { - dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis); - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - label = getAxisLabel(axis.axisInfo.highAxis); - if (label) { - dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue); - } else { - dump += StringPrintf(" / %d (split at %d)", axis.axisInfo.highAxis, - axis.axisInfo.splitValue); - } - } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { - dump += " (invert)"; - } - - dump += StringPrintf(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - dump += StringPrintf(INDENT4 " scale=%0.5f, offset=%0.5f, " - "highScale=%0.5f, highOffset=%0.5f\n", - axis.scale, axis.offset, axis.highScale, axis.highOffset); - dump += StringPrintf(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " - "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", - mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, - axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution); - } -} - -void JoystickInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Collect all axes. - for (int32_t abs = 0; abs <= ABS_MAX; abs++) { - if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) - & INPUT_DEVICE_CLASS_JOYSTICK)) { - continue; // axis must be claimed by a different device - } - - RawAbsoluteAxisInfo rawAxisInfo; - getAbsoluteAxisInfo(abs, &rawAxisInfo); - if (rawAxisInfo.valid) { - // Map axis. - AxisInfo axisInfo; - bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); - if (!explicitlyMapped) { - // Axis is not explicitly mapped, will choose a generic axis later. - axisInfo.mode = AxisInfo::MODE_NORMAL; - axisInfo.axis = -1; - } - - // Apply flat override. - int32_t rawFlat = axisInfo.flatOverride < 0 - ? rawAxisInfo.flat : axisInfo.flatOverride; - - // Calculate scaling factors and limits. - Axis axis; - if (axisInfo.mode == AxisInfo::MODE_SPLIT) { - float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); - float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, 0.0f, highScale, 0.0f, - 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else if (isCenteredAxis(axisInfo.axis)) { - float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, offset, scale, offset, - -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else { - float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, 0.0f, scale, 0.0f, - 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } - - // To eliminate noise while the joystick is at rest, filter out small variations - // in axis values up front. - axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f; - - mAxes.add(abs, axis); - } - } - - // If there are too many axes, start dropping them. - // Prefer to keep explicitly mapped axes. - if (mAxes.size() > PointerCoords::MAX_AXES) { - ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.", - getDeviceName().c_str(), mAxes.size(), PointerCoords::MAX_AXES); - pruneAxes(true); - pruneAxes(false); - } - - // Assign generic axis ids to remaining axes. - int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (axis.axisInfo.axis < 0) { - while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 - && haveAxis(nextGenericAxisId)) { - nextGenericAxisId += 1; - } - - if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { - axis.axisInfo.axis = nextGenericAxisId; - nextGenericAxisId += 1; - } else { - ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " - "have already been assigned to other axes.", - getDeviceName().c_str(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i--); - numAxes -= 1; - } - } - } - } -} - -bool JoystickInputMapper::haveAxis(int32_t axisId) { - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - if (axis.axisInfo.axis == axisId - || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT - && axis.axisInfo.highAxis == axisId)) { - return true; - } - } - return false; -} - -void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { - size_t i = mAxes.size(); - while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { - if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { - continue; - } - ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", - getDeviceName().c_str(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i); - } -} - -bool JoystickInputMapper::isCenteredAxis(int32_t axis) { - switch (axis) { - case AMOTION_EVENT_AXIS_X: - case AMOTION_EVENT_AXIS_Y: - case AMOTION_EVENT_AXIS_Z: - case AMOTION_EVENT_AXIS_RX: - case AMOTION_EVENT_AXIS_RY: - case AMOTION_EVENT_AXIS_RZ: - case AMOTION_EVENT_AXIS_HAT_X: - case AMOTION_EVENT_AXIS_HAT_Y: - case AMOTION_EVENT_AXIS_ORIENTATION: - case AMOTION_EVENT_AXIS_RUDDER: - case AMOTION_EVENT_AXIS_WHEEL: - return true; - default: - return false; - } -} - -void JoystickInputMapper::reset(nsecs_t when) { - // Recenter all axes. - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - axis.resetValue(); - } - - InputMapper::reset(when); -} - -void JoystickInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_ABS: { - ssize_t index = mAxes.indexOfKey(rawEvent->code); - if (index >= 0) { - Axis& axis = mAxes.editValueAt(index); - float newValue, highNewValue; - switch (axis.axisInfo.mode) { - case AxisInfo::MODE_INVERT: - newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) - * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - case AxisInfo::MODE_SPLIT: - if (rawEvent->value < axis.axisInfo.splitValue) { - newValue = (axis.axisInfo.splitValue - rawEvent->value) - * axis.scale + axis.offset; - highNewValue = 0.0f; - } else if (rawEvent->value > axis.axisInfo.splitValue) { - newValue = 0.0f; - highNewValue = (rawEvent->value - axis.axisInfo.splitValue) - * axis.highScale + axis.highOffset; - } else { - newValue = 0.0f; - highNewValue = 0.0f; - } - break; - default: - newValue = rawEvent->value * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - } - axis.newValue = newValue; - axis.highNewValue = highNewValue; - } - break; - } - - case EV_SYN: - switch (rawEvent->code) { - case SYN_REPORT: - sync(rawEvent->when, false /*force*/); - break; - } - break; - } -} - -void JoystickInputMapper::sync(nsecs_t when, bool force) { - if (!filterAxes(force)) { - return; - } - - int32_t metaState = mContext->getGlobalMetaState(); - int32_t buttonState = 0; - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, - axis.highCurrentValue); - } - } - - // Moving a joystick axis should not wake the device because joysticks can - // be fairly noisy even when not in use. On the other hand, pushing a gamepad - // button will likely wake the device. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {}); - getListener()->notifyMotion(&args); -} - -void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, - int32_t axis, float value) { - pointerCoords->setAxisValue(axis, value); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to produce - * values for the old axes as mirrors of the value of their corresponding - * new axes. */ - int32_t compatAxis = getCompatAxis(axis); - if (compatAxis >= 0) { - pointerCoords->setAxisValue(compatAxis, value); - } -} - -bool JoystickInputMapper::filterAxes(bool force) { - bool atLeastOneSignificantChange = force; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (force || hasValueChangedSignificantly(axis.filter, - axis.newValue, axis.currentValue, axis.min, axis.max)) { - axis.currentValue = axis.newValue; - atLeastOneSignificantChange = true; - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - if (force || hasValueChangedSignificantly(axis.filter, - axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) { - axis.highCurrentValue = axis.highNewValue; - atLeastOneSignificantChange = true; - } - } - } - return atLeastOneSignificantChange; -} - -bool JoystickInputMapper::hasValueChangedSignificantly( - float filter, float newValue, float currentValue, float min, float max) { - if (newValue != currentValue) { - // Filter out small changes in value unless the value is converging on the axis - // bounds or center point. This is intended to reduce the amount of information - // sent to applications by particularly noisy joysticks (such as PS3). - if (fabs(newValue - currentValue) > filter - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { - return true; - } - } - return false; -} - -bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange( - float filter, float newValue, float currentValue, float thresholdValue) { - float newDistance = fabs(newValue - thresholdValue); - if (newDistance < filter) { - float oldDistance = fabs(currentValue - thresholdValue); - if (newDistance < oldDistance) { - return true; - } - } - return false; -} - -} // namespace android diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h deleted file mode 100644 index 9777779e7d..0000000000 --- a/services/inputflinger/InputReader.h +++ /dev/null @@ -1,1809 +0,0 @@ -/* - * Copyright (C) 2010 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_READER_H -#define _UI_INPUT_READER_H - -#include "EventHub.h" -#include "PointerControllerInterface.h" -#include "InputListener.h" -#include "InputReaderBase.h" - -#include <input/DisplayViewport.h> -#include <input/Input.h> -#include <input/VelocityControl.h> -#include <input/VelocityTracker.h> -#include <ui/DisplayInfo.h> -#include <utils/KeyedVector.h> -#include <utils/Condition.h> -#include <utils/Mutex.h> -#include <utils/Timers.h> -#include <utils/BitSet.h> - -#include <optional> -#include <stddef.h> -#include <unistd.h> -#include <vector> - -namespace android { - -class InputDevice; -class InputMapper; - - -struct StylusState { - /* Time the stylus event was received. */ - nsecs_t when; - /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ - float pressure; - /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ - uint32_t buttons; - /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ - int32_t toolType; - - void copyFrom(const StylusState& other) { - when = other.when; - pressure = other.pressure; - buttons = other.buttons; - toolType = other.toolType; - } - - void clear() { - when = LLONG_MAX; - pressure = 0.f; - buttons = 0; - toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - } -}; - - -/* Internal interface used by individual input devices to access global input device state - * and parameters maintained by the input reader. - */ -class InputReaderContext { -public: - InputReaderContext() { } - virtual ~InputReaderContext() { } - - virtual void updateGlobalMetaState() = 0; - virtual int32_t getGlobalMetaState() = 0; - - virtual void disableVirtualKeysUntil(nsecs_t time) = 0; - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) = 0; - - virtual void fadePointer() = 0; - - virtual void requestTimeoutAtTime(nsecs_t when) = 0; - virtual int32_t bumpGeneration() = 0; - - virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) = 0; - virtual void dispatchExternalStylusState(const StylusState& outState) = 0; - - virtual InputReaderPolicyInterface* getPolicy() = 0; - virtual InputListenerInterface* getListener() = 0; - virtual EventHubInterface* getEventHub() = 0; - - virtual uint32_t getNextSequenceNum() = 0; -}; - - -/* The input reader reads raw event data from the event hub and processes it into input events - * that it sends to the input listener. Some functions of the input reader, such as early - * event filtering in low power states, are controlled by a separate policy object. - * - * The InputReader owns a collection of InputMappers. Most of the work it does happens - * on the input reader thread but the InputReader can receive queries from other system - * components running on arbitrary threads. To keep things manageable, the InputReader - * uses a single Mutex to guard its state. The Mutex may be held while calling into the - * EventHub or the InputReaderPolicy but it is never held while calling into the - * InputListener. - */ -class InputReader : public InputReaderInterface { -public: - InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener); - virtual ~InputReader(); - - virtual void dump(std::string& dump); - virtual void monitor(); - - virtual void loopOnce(); - - virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices); - - virtual bool isInputDeviceEnabled(int32_t deviceId); - - virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode); - virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode); - virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, - int32_t sw); - - virtual void toggleCapsLockState(int32_t deviceId); - - virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); - - virtual void requestRefreshConfiguration(uint32_t changes); - - virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token); - virtual void cancelVibrate(int32_t deviceId, int32_t token); - - virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId); -protected: - // These members are protected so they can be instrumented by test cases. - virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, uint32_t classes); - - class ContextImpl : public InputReaderContext { - InputReader* mReader; - - public: - explicit ContextImpl(InputReader* reader); - - virtual void updateGlobalMetaState(); - virtual int32_t getGlobalMetaState(); - virtual void disableVirtualKeysUntil(nsecs_t time); - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode); - virtual void fadePointer(); - virtual void requestTimeoutAtTime(nsecs_t when); - virtual int32_t bumpGeneration(); - virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices); - virtual void dispatchExternalStylusState(const StylusState& outState); - virtual InputReaderPolicyInterface* getPolicy(); - virtual InputListenerInterface* getListener(); - virtual EventHubInterface* getEventHub(); - virtual uint32_t getNextSequenceNum(); - } mContext; - - friend class ContextImpl; - -private: - Mutex mLock; - - Condition mReaderIsAliveCondition; - - sp<EventHubInterface> mEventHub; - sp<InputReaderPolicyInterface> mPolicy; - sp<QueuedInputListener> mQueuedListener; - - InputReaderConfiguration mConfig; - - // used by InputReaderContext::getNextSequenceNum() as a counter for event sequence numbers - uint32_t mNextSequenceNum; - - // The event queue. - static const int EVENT_BUFFER_SIZE = 256; - RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; - - KeyedVector<int32_t, InputDevice*> mDevices; - - // low-level input event decoding and device management - void processEventsLocked(const RawEvent* rawEvents, size_t count); - - void addDeviceLocked(nsecs_t when, int32_t deviceId); - void removeDeviceLocked(nsecs_t when, int32_t deviceId); - void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); - void timeoutExpiredLocked(nsecs_t when); - - void handleConfigurationChangedLocked(nsecs_t when); - - int32_t mGlobalMetaState; - void updateGlobalMetaStateLocked(); - int32_t getGlobalMetaStateLocked(); - - void notifyExternalStylusPresenceChanged(); - void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices); - void dispatchExternalStylusState(const StylusState& state); - - void fadePointerLocked(); - - int32_t mGeneration; - int32_t bumpGenerationLocked(); - - void getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices); - - nsecs_t mDisableVirtualKeysTimeout; - void disableVirtualKeysUntilLocked(nsecs_t time); - bool shouldDropVirtualKeyLocked(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode); - - nsecs_t mNextTimeout; - void requestTimeoutAtTimeLocked(nsecs_t when); - - uint32_t mConfigurationChangesToRefresh; - void refreshConfigurationLocked(uint32_t changes); - - // state queries - typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc); - bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); -}; - - -/* Represents the state of a single input device. */ -class InputDevice { -public: - InputDevice(InputReaderContext* context, int32_t id, int32_t generation, int32_t - controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes); - ~InputDevice(); - - inline InputReaderContext* getContext() { return mContext; } - inline int32_t getId() const { return mId; } - inline int32_t getControllerNumber() const { return mControllerNumber; } - inline int32_t getGeneration() const { return mGeneration; } - inline const std::string getName() const { return mIdentifier.name; } - inline const std::string getDescriptor() { return mIdentifier.descriptor; } - inline uint32_t getClasses() const { return mClasses; } - inline uint32_t getSources() const { return mSources; } - - inline bool isExternal() { return mIsExternal; } - inline void setExternal(bool external) { mIsExternal = external; } - inline std::optional<uint8_t> getAssociatedDisplayPort() const { - return mAssociatedDisplayPort; - } - - inline void setMic(bool hasMic) { mHasMic = hasMic; } - inline bool hasMic() const { return mHasMic; } - - inline bool isIgnored() { return mMappers.empty(); } - - bool isEnabled(); - void setEnabled(bool enabled, nsecs_t when); - - void dump(std::string& dump); - void addMapper(InputMapper* mapper); - void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - void reset(nsecs_t when); - void process(const RawEvent* rawEvents, size_t count); - void timeoutExpired(nsecs_t when); - void updateExternalStylusState(const StylusState& state); - - void getDeviceInfo(InputDeviceInfo* outDeviceInfo); - int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); - void cancelVibrate(int32_t token); - void cancelTouch(nsecs_t when); - - int32_t getMetaState(); - void updateMetaState(int32_t keyCode); - - void fadePointer(); - - void bumpGeneration(); - - void notifyReset(nsecs_t when); - - inline const PropertyMap& getConfiguration() { return mConfiguration; } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - bool hasKey(int32_t code) { - return getEventHub()->hasScanCode(mId, code); - } - - bool hasAbsoluteAxis(int32_t code) { - RawAbsoluteAxisInfo info; - getEventHub()->getAbsoluteAxisInfo(mId, code, &info); - return info.valid; - } - - bool isKeyPressed(int32_t code) { - return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; - } - - int32_t getAbsoluteAxisValue(int32_t code) { - int32_t value; - getEventHub()->getAbsoluteAxisValue(mId, code, &value); - return value; - } - - std::optional<int32_t> getAssociatedDisplay(); -private: - InputReaderContext* mContext; - int32_t mId; - int32_t mGeneration; - int32_t mControllerNumber; - InputDeviceIdentifier mIdentifier; - std::string mAlias; - uint32_t mClasses; - - std::vector<InputMapper*> mMappers; - - uint32_t mSources; - bool mIsExternal; - std::optional<uint8_t> mAssociatedDisplayPort; - bool mHasMic; - bool mDropUntilNextSync; - - typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); - - PropertyMap mConfiguration; -}; - - -/* Keeps track of the state of mouse or touch pad buttons. */ -class CursorButtonAccumulator { -public: - CursorButtonAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - -private: - bool mBtnLeft; - bool mBtnRight; - bool mBtnMiddle; - bool mBtnBack; - bool mBtnSide; - bool mBtnForward; - bool mBtnExtra; - bool mBtnTask; - - void clearButtons(); -}; - - -/* Keeps track of cursor movements. */ - -class CursorMotionAccumulator { -public: - CursorMotionAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - -private: - int32_t mRelX; - int32_t mRelY; - - void clearRelativeAxes(); -}; - - -/* Keeps track of cursor scrolling motions. */ - -class CursorScrollAccumulator { -public: - CursorScrollAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline bool haveRelativeVWheel() const { return mHaveRelWheel; } - inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - inline int32_t getRelativeVWheel() const { return mRelWheel; } - inline int32_t getRelativeHWheel() const { return mRelHWheel; } - -private: - bool mHaveRelWheel; - bool mHaveRelHWheel; - - int32_t mRelX; - int32_t mRelY; - int32_t mRelWheel; - int32_t mRelHWheel; - - void clearRelativeAxes(); -}; - - -/* Keeps track of the state of touch, stylus and tool buttons. */ -class TouchButtonAccumulator { -public: - TouchButtonAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - int32_t getToolType() const; - bool isToolActive() const; - bool isHovering() const; - bool hasStylus() const; - -private: - bool mHaveBtnTouch; - bool mHaveStylus; - - bool mBtnTouch; - bool mBtnStylus; - bool mBtnStylus2; - bool mBtnToolFinger; - bool mBtnToolPen; - bool mBtnToolRubber; - bool mBtnToolBrush; - bool mBtnToolPencil; - bool mBtnToolAirbrush; - bool mBtnToolMouse; - bool mBtnToolLens; - bool mBtnToolDoubleTap; - bool mBtnToolTripleTap; - bool mBtnToolQuadTap; - - void clearButtons(); -}; - - -/* Raw axis information from the driver. */ -struct RawPointerAxes { - RawAbsoluteAxisInfo x; - RawAbsoluteAxisInfo y; - RawAbsoluteAxisInfo pressure; - RawAbsoluteAxisInfo touchMajor; - RawAbsoluteAxisInfo touchMinor; - RawAbsoluteAxisInfo toolMajor; - RawAbsoluteAxisInfo toolMinor; - RawAbsoluteAxisInfo orientation; - RawAbsoluteAxisInfo distance; - RawAbsoluteAxisInfo tiltX; - RawAbsoluteAxisInfo tiltY; - RawAbsoluteAxisInfo trackingId; - RawAbsoluteAxisInfo slot; - - RawPointerAxes(); - inline int32_t getRawWidth() const { return x.maxValue - x.minValue + 1; } - inline int32_t getRawHeight() const { return y.maxValue - y.minValue + 1; } - void clear(); -}; - - -/* Raw data for a collection of pointers including a pointer id mapping table. */ -struct RawPointerData { - struct Pointer { - uint32_t id; - int32_t x; - int32_t y; - int32_t pressure; - int32_t touchMajor; - int32_t touchMinor; - int32_t toolMajor; - int32_t toolMinor; - int32_t orientation; - int32_t distance; - int32_t tiltX; - int32_t tiltY; - int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant - bool isHovering; - }; - - uint32_t pointerCount; - Pointer pointers[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - RawPointerData(); - void clear(); - void copyFrom(const RawPointerData& other); - void getCentroidOfTouchingPointers(float* outX, float* outY) const; - - inline void markIdBit(uint32_t id, bool isHovering) { - if (isHovering) { - hoveringIdBits.markBit(id); - } else { - touchingIdBits.markBit(id); - } - } - - inline void clearIdBits() { - hoveringIdBits.clear(); - touchingIdBits.clear(); - } - - inline const Pointer& pointerForId(uint32_t id) const { - return pointers[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) { - return pointers[pointerIndex].isHovering; - } -}; - - -/* Cooked data for a collection of pointers including a pointer id mapping table. */ -struct CookedPointerData { - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - CookedPointerData(); - void clear(); - void copyFrom(const CookedPointerData& other); - - inline const PointerCoords& pointerCoordsForId(uint32_t id) const { - return pointerCoords[idToIndex[id]]; - } - - inline PointerCoords& editPointerCoordsWithId(uint32_t id) { - return pointerCoords[idToIndex[id]]; - } - - inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { - return pointerProperties[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) const { - return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); - } - - inline bool isTouching(uint32_t pointerIndex) const { - return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); - } -}; - -/** - * Basic statistics information. - * Keep track of min, max, average, and standard deviation of the received samples. - * Used to report latency information about input events. - */ -struct LatencyStatistics { - float min; - float max; - // Sum of all samples - float sum; - // Sum of squares of all samples - float sum2; - // The number of samples - size_t count; - // The last time statistics were reported. - nsecs_t lastReportTime; - - LatencyStatistics() { - reset(systemTime(SYSTEM_TIME_MONOTONIC)); - } - - inline void addValue(float x) { - if (x < min) { - min = x; - } - if (x > max) { - max = x; - } - sum += x; - sum2 += x * x; - count++; - } - - // Get the average value. Should not be called if no samples have been added. - inline float mean() { - if (count == 0) { - return 0; - } - return sum / count; - } - - // Get the standard deviation. Should not be called if no samples have been added. - inline float stdev() { - if (count == 0) { - return 0; - } - float average = mean(); - return sqrt(sum2 / count - average * average); - } - - /** - * Reset internal state. The variable 'when' is the time when the data collection started. - * Call this to start a new data collection window. - */ - inline void reset(nsecs_t when) { - max = 0; - min = std::numeric_limits<float>::max(); - sum = 0; - sum2 = 0; - count = 0; - lastReportTime = when; - } -}; - -/* Keeps track of the state of single-touch protocol. */ -class SingleTouchMotionAccumulator { -public: - SingleTouchMotionAccumulator(); - - void process(const RawEvent* rawEvent); - void reset(InputDevice* device); - - inline int32_t getAbsoluteX() const { return mAbsX; } - inline int32_t getAbsoluteY() const { return mAbsY; } - inline int32_t getAbsolutePressure() const { return mAbsPressure; } - inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } - inline int32_t getAbsoluteDistance() const { return mAbsDistance; } - inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } - inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } - -private: - int32_t mAbsX; - int32_t mAbsY; - int32_t mAbsPressure; - int32_t mAbsToolWidth; - int32_t mAbsDistance; - int32_t mAbsTiltX; - int32_t mAbsTiltY; - - void clearAbsoluteAxes(); -}; - - -/* Keeps track of the state of multi-touch protocol. */ -class MultiTouchMotionAccumulator { -public: - class Slot { - public: - inline bool isInUse() const { return mInUse; } - inline int32_t getX() const { return mAbsMTPositionX; } - inline int32_t getY() const { return mAbsMTPositionY; } - inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } - inline int32_t getTouchMinor() const { - return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } - inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } - inline int32_t getToolMinor() const { - return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } - inline int32_t getOrientation() const { return mAbsMTOrientation; } - inline int32_t getTrackingId() const { return mAbsMTTrackingId; } - inline int32_t getPressure() const { return mAbsMTPressure; } - inline int32_t getDistance() const { return mAbsMTDistance; } - inline int32_t getToolType() const; - - private: - friend class MultiTouchMotionAccumulator; - - bool mInUse; - bool mHaveAbsMTTouchMinor; - bool mHaveAbsMTWidthMinor; - bool mHaveAbsMTToolType; - - int32_t mAbsMTPositionX; - int32_t mAbsMTPositionY; - int32_t mAbsMTTouchMajor; - int32_t mAbsMTTouchMinor; - int32_t mAbsMTWidthMajor; - int32_t mAbsMTWidthMinor; - int32_t mAbsMTOrientation; - int32_t mAbsMTTrackingId; - int32_t mAbsMTPressure; - int32_t mAbsMTDistance; - int32_t mAbsMTToolType; - - Slot(); - void clear(); - }; - - MultiTouchMotionAccumulator(); - ~MultiTouchMotionAccumulator(); - - void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); - void reset(InputDevice* device); - void process(const RawEvent* rawEvent); - void finishSync(); - bool hasStylus() const; - - inline size_t getSlotCount() const { return mSlotCount; } - inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } - inline uint32_t getDeviceTimestamp() const { return mDeviceTimestamp; } - -private: - int32_t mCurrentSlot; - Slot* mSlots; - size_t mSlotCount; - bool mUsingSlotsProtocol; - bool mHaveStylus; - uint32_t mDeviceTimestamp; - - void clearSlots(int32_t initialSlot); -}; - - -/* An input mapper transforms raw input events into cooked event data. - * A single input device can have multiple associated input mappers in order to interpret - * different classes of events. - * - * InputMapper lifecycle: - * - create - * - configure with 0 changes - * - reset - * - process, process, process (may occasionally reconfigure with non-zero changes or reset) - * - reset - * - destroy - */ -class InputMapper { -public: - explicit InputMapper(InputDevice* device); - virtual ~InputMapper(); - - inline InputDevice* getDevice() { return mDevice; } - inline int32_t getDeviceId() { return mDevice->getId(); } - inline const std::string getDeviceName() { return mDevice->getName(); } - inline InputReaderContext* getContext() { return mContext; } - inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } - inline InputListenerInterface* getListener() { return mContext->getListener(); } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - virtual uint32_t getSources() = 0; - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent) = 0; - virtual void timeoutExpired(nsecs_t when); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token); - virtual void cancelVibrate(int32_t token); - virtual void cancelTouch(nsecs_t when); - - virtual int32_t getMetaState(); - virtual void updateMetaState(int32_t keyCode); - - virtual void updateExternalStylusState(const StylusState& state); - - virtual void fadePointer(); - virtual std::optional<int32_t> getAssociatedDisplay() { - return std::nullopt; - } -protected: - InputDevice* mDevice; - InputReaderContext* mContext; - - status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); - void bumpGeneration(); - - static void dumpRawAbsoluteAxisInfo(std::string& dump, - const RawAbsoluteAxisInfo& axis, const char* name); - static void dumpStylusState(std::string& dump, const StylusState& state); -}; - - -class SwitchInputMapper : public InputMapper { -public: - explicit SwitchInputMapper(InputDevice* device); - virtual ~SwitchInputMapper(); - - virtual uint32_t getSources(); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - virtual void dump(std::string& dump); - -private: - uint32_t mSwitchValues; - uint32_t mUpdatedSwitchMask; - - void processSwitch(int32_t switchCode, int32_t switchValue); - void sync(nsecs_t when); -}; - - -class VibratorInputMapper : public InputMapper { -public: - explicit VibratorInputMapper(InputDevice* device); - virtual ~VibratorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void process(const RawEvent* rawEvent); - - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token); - virtual void cancelVibrate(int32_t token); - virtual void timeoutExpired(nsecs_t when); - virtual void dump(std::string& dump); - -private: - bool mVibrating; - nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; - size_t mPatternSize; - ssize_t mRepeat; - int32_t mToken; - ssize_t mIndex; - nsecs_t mNextStepTime; - - void nextStep(); - void stopVibrating(); -}; - - -class KeyboardInputMapper : public InputMapper { -public: - KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); - virtual ~KeyboardInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual int32_t getMetaState(); - virtual void updateMetaState(int32_t keyCode); - -private: - // The current viewport. - std::optional<DisplayViewport> mViewport; - - struct KeyDown { - int32_t keyCode; - int32_t scanCode; - }; - - uint32_t mSource; - int32_t mKeyboardType; - - std::vector<KeyDown> mKeyDowns; // keys that are down - int32_t mMetaState; - nsecs_t mDownTime; // time of most recent key down - - int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none - - struct LedState { - bool avail; // led is available - bool on; // we think the led is currently on - }; - LedState mCapsLockLedState; - LedState mNumLockLedState; - LedState mScrollLockLedState; - - // Immutable configuration parameters. - struct Parameters { - bool orientationAware; - bool handlesKeyRepeat; - } mParameters; - - void configureParameters(); - void dumpParameters(std::string& dump); - - int32_t getOrientation(); - int32_t getDisplayId(); - - bool isKeyboardOrGamepadKey(int32_t scanCode); - bool isMediaKey(int32_t keyCode); - - void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode); - - bool updateMetaStateIfNeeded(int32_t keyCode, bool down); - - ssize_t findKeyDown(int32_t scanCode); - - void resetLedState(); - void initializeLedState(LedState& ledState, int32_t led); - void updateLedState(bool reset); - void updateLedStateForModifier(LedState& ledState, int32_t led, - int32_t modifier, bool reset); -}; - - -class CursorInputMapper : public InputMapper { -public: - explicit CursorInputMapper(InputDevice* device); - virtual ~CursorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - - virtual void fadePointer(); - - virtual std::optional<int32_t> getAssociatedDisplay(); -private: - // Amount that trackball needs to move in order to generate a key event. - static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; - - // Immutable configuration parameters. - struct Parameters { - enum Mode { - MODE_POINTER, - MODE_POINTER_RELATIVE, - MODE_NAVIGATION, - }; - - Mode mode; - bool hasAssociatedDisplay; - bool orientationAware; - } mParameters; - - CursorButtonAccumulator mCursorButtonAccumulator; - CursorMotionAccumulator mCursorMotionAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - - int32_t mSource; - float mXScale; - float mYScale; - float mXPrecision; - float mYPrecision; - - float mVWheelScale; - float mHWheelScale; - - // Velocity controls for mouse pointer and wheel movements. - // The controls for X and Y wheel movements are separate to keep them decoupled. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - int32_t mOrientation; - - sp<PointerControllerInterface> mPointerController; - - int32_t mButtonState; - nsecs_t mDownTime; - - void configureParameters(); - void dumpParameters(std::string& dump); - - void sync(nsecs_t when); -}; - - -class RotaryEncoderInputMapper : public InputMapper { -public: - explicit RotaryEncoderInputMapper(InputDevice* device); - virtual ~RotaryEncoderInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -private: - CursorScrollAccumulator mRotaryEncoderScrollAccumulator; - - int32_t mSource; - float mScalingFactor; - int32_t mOrientation; - - void sync(nsecs_t when); -}; - -class TouchInputMapper : public InputMapper { -public: - explicit TouchInputMapper(InputDevice* device); - virtual ~TouchInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual void fadePointer(); - virtual void cancelTouch(nsecs_t when); - virtual void timeoutExpired(nsecs_t when); - virtual void updateExternalStylusState(const StylusState& state); - virtual std::optional<int32_t> getAssociatedDisplay(); -protected: - CursorButtonAccumulator mCursorButtonAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - TouchButtonAccumulator mTouchButtonAccumulator; - - struct VirtualKey { - int32_t keyCode; - int32_t scanCode; - uint32_t flags; - - // computed hit box, specified in touch screen coords based on known display size - int32_t hitLeft; - int32_t hitTop; - int32_t hitRight; - int32_t hitBottom; - - inline bool isHit(int32_t x, int32_t y) const { - return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; - } - }; - - // Input sources and device mode. - uint32_t mSource; - - enum DeviceMode { - DEVICE_MODE_DISABLED, // input is disabled - DEVICE_MODE_DIRECT, // direct mapping (touchscreen) - DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) - DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation) - DEVICE_MODE_POINTER, // pointer mapping (pointer) - }; - DeviceMode mDeviceMode; - - // The reader's configuration. - InputReaderConfiguration mConfig; - - // Immutable configuration parameters. - struct Parameters { - enum DeviceType { - DEVICE_TYPE_TOUCH_SCREEN, - DEVICE_TYPE_TOUCH_PAD, - DEVICE_TYPE_TOUCH_NAVIGATION, - DEVICE_TYPE_POINTER, - }; - - DeviceType deviceType; - bool hasAssociatedDisplay; - bool associatedDisplayIsExternal; - bool orientationAware; - bool hasButtonUnderPad; - std::string uniqueDisplayId; - - enum GestureMode { - GESTURE_MODE_SINGLE_TOUCH, - GESTURE_MODE_MULTI_TOUCH, - }; - GestureMode gestureMode; - - bool wake; - } mParameters; - - // Immutable calibration parameters in parsed form. - struct Calibration { - // Size - enum SizeCalibration { - SIZE_CALIBRATION_DEFAULT, - SIZE_CALIBRATION_NONE, - SIZE_CALIBRATION_GEOMETRIC, - SIZE_CALIBRATION_DIAMETER, - SIZE_CALIBRATION_BOX, - SIZE_CALIBRATION_AREA, - }; - - SizeCalibration sizeCalibration; - - bool haveSizeScale; - float sizeScale; - bool haveSizeBias; - float sizeBias; - bool haveSizeIsSummed; - bool sizeIsSummed; - - // Pressure - enum PressureCalibration { - PRESSURE_CALIBRATION_DEFAULT, - PRESSURE_CALIBRATION_NONE, - PRESSURE_CALIBRATION_PHYSICAL, - PRESSURE_CALIBRATION_AMPLITUDE, - }; - - PressureCalibration pressureCalibration; - bool havePressureScale; - float pressureScale; - - // Orientation - enum OrientationCalibration { - ORIENTATION_CALIBRATION_DEFAULT, - ORIENTATION_CALIBRATION_NONE, - ORIENTATION_CALIBRATION_INTERPOLATED, - ORIENTATION_CALIBRATION_VECTOR, - }; - - OrientationCalibration orientationCalibration; - - // Distance - enum DistanceCalibration { - DISTANCE_CALIBRATION_DEFAULT, - DISTANCE_CALIBRATION_NONE, - DISTANCE_CALIBRATION_SCALED, - }; - - DistanceCalibration distanceCalibration; - bool haveDistanceScale; - float distanceScale; - - enum CoverageCalibration { - COVERAGE_CALIBRATION_DEFAULT, - COVERAGE_CALIBRATION_NONE, - COVERAGE_CALIBRATION_BOX, - }; - - CoverageCalibration coverageCalibration; - - inline void applySizeScaleAndBias(float* outSize) const { - if (haveSizeScale) { - *outSize *= sizeScale; - } - if (haveSizeBias) { - *outSize += sizeBias; - } - if (*outSize < 0) { - *outSize = 0; - } - } - } mCalibration; - - // Affine location transformation/calibration - struct TouchAffineTransformation mAffineTransform; - - RawPointerAxes mRawPointerAxes; - - struct RawState { - nsecs_t when; - uint32_t deviceTimestamp; - - // Raw pointer sample data. - RawPointerData rawPointerData; - - int32_t buttonState; - - // Scroll state. - int32_t rawVScroll; - int32_t rawHScroll; - - void copyFrom(const RawState& other) { - when = other.when; - deviceTimestamp = other.deviceTimestamp; - rawPointerData.copyFrom(other.rawPointerData); - buttonState = other.buttonState; - rawVScroll = other.rawVScroll; - rawHScroll = other.rawHScroll; - } - - void clear() { - when = 0; - deviceTimestamp = 0; - rawPointerData.clear(); - buttonState = 0; - rawVScroll = 0; - rawHScroll = 0; - } - }; - - struct CookedState { - uint32_t deviceTimestamp; - // Cooked pointer sample data. - CookedPointerData cookedPointerData; - - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 fingerIdBits; - BitSet32 stylusIdBits; - BitSet32 mouseIdBits; - - int32_t buttonState; - - void copyFrom(const CookedState& other) { - deviceTimestamp = other.deviceTimestamp; - cookedPointerData.copyFrom(other.cookedPointerData); - fingerIdBits = other.fingerIdBits; - stylusIdBits = other.stylusIdBits; - mouseIdBits = other.mouseIdBits; - buttonState = other.buttonState; - } - - void clear() { - deviceTimestamp = 0; - cookedPointerData.clear(); - fingerIdBits.clear(); - stylusIdBits.clear(); - mouseIdBits.clear(); - buttonState = 0; - } - }; - - std::vector<RawState> mRawStatesPending; - RawState mCurrentRawState; - CookedState mCurrentCookedState; - RawState mLastRawState; - CookedState mLastCookedState; - - // State provided by an external stylus - StylusState mExternalStylusState; - int64_t mExternalStylusId; - nsecs_t mExternalStylusFusionTimeout; - bool mExternalStylusDataPending; - - // True if we sent a HOVER_ENTER event. - bool mSentHoverEnter; - - // Have we assigned pointer IDs for this stream - bool mHavePointerIds; - - // Is the current stream of direct touch events aborted - bool mCurrentMotionAborted; - - // The time the primary pointer last went down. - nsecs_t mDownTime; - - // The pointer controller, or null if the device is not a pointer. - sp<PointerControllerInterface> mPointerController; - - std::vector<VirtualKey> mVirtualKeys; - - virtual void configureParameters(); - virtual void dumpParameters(std::string& dump); - virtual void configureRawPointerAxes(); - virtual void dumpRawPointerAxes(std::string& dump); - virtual void configureSurface(nsecs_t when, bool* outResetNeeded); - virtual void dumpSurface(std::string& dump); - virtual void configureVirtualKeys(); - virtual void dumpVirtualKeys(std::string& dump); - virtual void parseCalibration(); - virtual void resolveCalibration(); - virtual void dumpCalibration(std::string& dump); - virtual void updateAffineTransformation(); - virtual void dumpAffineTransformation(std::string& dump); - virtual void resolveExternalStylusPresence(); - virtual bool hasStylus() const = 0; - virtual bool hasExternalStylus() const; - - virtual void syncTouch(nsecs_t when, RawState* outState) = 0; - -private: - // The current viewport. - // The components of the viewport are specified in the display's rotated orientation. - DisplayViewport mViewport; - - // The surface orientation, width and height set by configureSurface(). - // The width and height are derived from the viewport but are specified - // in the natural orientation. - // The surface origin specifies how the surface coordinates should be translated - // to align with the logical display coordinate space. - int32_t mSurfaceWidth; - int32_t mSurfaceHeight; - int32_t mSurfaceLeft; - int32_t mSurfaceTop; - - // Similar to the surface coordinates, but in the raw display coordinate space rather than in - // the logical coordinate space. - int32_t mPhysicalWidth; - int32_t mPhysicalHeight; - int32_t mPhysicalLeft; - int32_t mPhysicalTop; - - // The orientation may be different from the viewport orientation as it specifies - // the rotation of the surface coordinates required to produce the viewport's - // requested orientation, so it will depend on whether the device is orientation aware. - int32_t mSurfaceOrientation; - - // Translation and scaling factors, orientation-independent. - float mXTranslate; - float mXScale; - float mXPrecision; - - float mYTranslate; - float mYScale; - float mYPrecision; - - float mGeometricScale; - - float mPressureScale; - - float mSizeScale; - - float mOrientationScale; - - float mDistanceScale; - - bool mHaveTilt; - float mTiltXCenter; - float mTiltXScale; - float mTiltYCenter; - float mTiltYScale; - - bool mExternalStylusConnected; - - // Oriented motion ranges for input device info. - struct OrientedRanges { - InputDeviceInfo::MotionRange x; - InputDeviceInfo::MotionRange y; - InputDeviceInfo::MotionRange pressure; - - bool haveSize; - InputDeviceInfo::MotionRange size; - - bool haveTouchSize; - InputDeviceInfo::MotionRange touchMajor; - InputDeviceInfo::MotionRange touchMinor; - - bool haveToolSize; - InputDeviceInfo::MotionRange toolMajor; - InputDeviceInfo::MotionRange toolMinor; - - bool haveOrientation; - InputDeviceInfo::MotionRange orientation; - - bool haveDistance; - InputDeviceInfo::MotionRange distance; - - bool haveTilt; - InputDeviceInfo::MotionRange tilt; - - OrientedRanges() { - clear(); - } - - void clear() { - haveSize = false; - haveTouchSize = false; - haveToolSize = false; - haveOrientation = false; - haveDistance = false; - haveTilt = false; - } - } mOrientedRanges; - - // Oriented dimensions and precision. - float mOrientedXPrecision; - float mOrientedYPrecision; - - struct CurrentVirtualKeyState { - bool down; - bool ignored; - nsecs_t downTime; - int32_t keyCode; - int32_t scanCode; - } mCurrentVirtualKey; - - // Scale factor for gesture or mouse based pointer movements. - float mPointerXMovementScale; - float mPointerYMovementScale; - - // Scale factor for gesture based zooming and other freeform motions. - float mPointerXZoomScale; - float mPointerYZoomScale; - - // The maximum swipe width. - float mPointerGestureMaxSwipeWidth; - - struct PointerDistanceHeapElement { - uint32_t currentPointerIndex : 8; - uint32_t lastPointerIndex : 8; - uint64_t distance : 48; // squared distance - }; - - enum PointerUsage { - POINTER_USAGE_NONE, - POINTER_USAGE_GESTURES, - POINTER_USAGE_STYLUS, - POINTER_USAGE_MOUSE, - }; - PointerUsage mPointerUsage; - - struct PointerGesture { - enum Mode { - // No fingers, button is not pressed. - // Nothing happening. - NEUTRAL, - - // No fingers, button is not pressed. - // Tap detected. - // Emits DOWN and UP events at the pointer location. - TAP, - - // Exactly one finger dragging following a tap. - // Pointer follows the active finger. - // Emits DOWN, MOVE and UP events at the pointer location. - // - // Detect double-taps when the finger goes up while in TAP_DRAG mode. - TAP_DRAG, - - // Button is pressed. - // Pointer follows the active finger if there is one. Other fingers are ignored. - // Emits DOWN, MOVE and UP events at the pointer location. - BUTTON_CLICK_OR_DRAG, - - // Exactly one finger, button is not pressed. - // Pointer follows the active finger. - // Emits HOVER_MOVE events at the pointer location. - // - // Detect taps when the finger goes up while in HOVER mode. - HOVER, - - // Exactly two fingers but neither have moved enough to clearly indicate - // whether a swipe or freeform gesture was intended. We consider the - // pointer to be pressed so this enables clicking or long-pressing on buttons. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. - PRESS, - - // Exactly two fingers moving in the same direction, button is not pressed. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single pointer coordinate that - // follows the midpoint between both fingers. - SWIPE, - - // Two or more fingers moving in arbitrary directions, button is not pressed. - // Pointer does not move. - // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow - // each finger individually relative to the initial centroid of the finger. - FREEFORM, - - // Waiting for quiet time to end before starting the next gesture. - QUIET, - }; - - // Time the first finger went down. - nsecs_t firstTouchTime; - - // The active pointer id from the raw touch data. - int32_t activeTouchId; // -1 if none - - // The active pointer id from the gesture last delivered to the application. - int32_t activeGestureId; // -1 if none - - // Pointer coords and ids for the current and previous pointer gesture. - Mode currentGestureMode; - BitSet32 currentGestureIdBits; - uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties currentGestureProperties[MAX_POINTERS]; - PointerCoords currentGestureCoords[MAX_POINTERS]; - - Mode lastGestureMode; - BitSet32 lastGestureIdBits; - uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties lastGestureProperties[MAX_POINTERS]; - PointerCoords lastGestureCoords[MAX_POINTERS]; - - // Time the pointer gesture last went down. - nsecs_t downTime; - - // Time when the pointer went down for a TAP. - nsecs_t tapDownTime; - - // Time when the pointer went up for a TAP. - nsecs_t tapUpTime; - - // Location of initial tap. - float tapX, tapY; - - // Time we started waiting for quiescence. - nsecs_t quietTime; - - // Reference points for multitouch gestures. - float referenceTouchX; // reference touch X/Y coordinates in surface units - float referenceTouchY; - float referenceGestureX; // reference gesture X/Y coordinates in pixels - float referenceGestureY; - - // Distance that each pointer has traveled which has not yet been - // subsumed into the reference gesture position. - BitSet32 referenceIdBits; - struct Delta { - float dx, dy; - }; - Delta referenceDeltas[MAX_POINTER_ID + 1]; - - // Describes how touch ids are mapped to gesture ids for freeform gestures. - uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; - - // A velocity tracker for determining whether to switch active pointers during drags. - VelocityTracker velocityTracker; - - void reset() { - firstTouchTime = LLONG_MIN; - activeTouchId = -1; - activeGestureId = -1; - currentGestureMode = NEUTRAL; - currentGestureIdBits.clear(); - lastGestureMode = NEUTRAL; - lastGestureIdBits.clear(); - downTime = 0; - velocityTracker.clear(); - resetTap(); - resetQuietTime(); - } - - void resetTap() { - tapDownTime = LLONG_MIN; - tapUpTime = LLONG_MIN; - } - - void resetQuietTime() { - quietTime = LLONG_MIN; - } - } mPointerGesture; - - struct PointerSimple { - PointerCoords currentCoords; - PointerProperties currentProperties; - PointerCoords lastCoords; - PointerProperties lastProperties; - - // True if the pointer is down. - bool down; - - // True if the pointer is hovering. - bool hovering; - - // Time the pointer last went down. - nsecs_t downTime; - - void reset() { - currentCoords.clear(); - currentProperties.clear(); - lastCoords.clear(); - lastProperties.clear(); - down = false; - hovering = false; - downTime = 0; - } - } mPointerSimple; - - // The pointer and scroll velocity controls. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - // Latency statistics for touch events - struct LatencyStatistics mStatistics; - - std::optional<DisplayViewport> findViewport(); - - void resetExternalStylus(); - void clearStylusDataPendingFlags(); - - void sync(nsecs_t when); - - bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); - void processRawTouches(bool timeout); - void cookAndDispatch(nsecs_t when); - void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags); - - void dispatchTouches(nsecs_t when, uint32_t policyFlags); - void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); - void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); - void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags); - void dispatchButtonPress(nsecs_t when, uint32_t policyFlags); - const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData); - void cookPointerData(); - void abortTouches(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); - void abortPointerUsage(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); - void abortPointerGestures(nsecs_t when, uint32_t policyFlags); - bool preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, - bool isTimeout); - - void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); - void abortPointerStylus(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); - void abortPointerMouse(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, - bool down, bool hovering); - void abortPointerSimple(nsecs_t when, uint32_t policyFlags); - - bool assignExternalStylusId(const RawState& state, bool timeout); - void applyExternalStylusButtonState(nsecs_t when); - void applyExternalStylusTouchState(nsecs_t when); - - // Dispatches a motion event. - // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the - // method will take care of setting the index and transmuting the action to DOWN or UP - // it is the first / last pointer to go down / up. - void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t actionButton, - int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, - uint32_t deviceTimestamp, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); - - // Updates pointer coords and properties for pointers with specified ids that have moved. - // Returns true if any of them changed. - bool updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerProperties* outProperties, PointerCoords* outCoords, - const uint32_t* outIdToIndex, BitSet32 idBits) const; - - bool isPointInsideSurface(int32_t x, int32_t y); - const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - - static void assignPointerIds(const RawState* last, RawState* current); - - void reportEventForStatistics(nsecs_t evdevTime); - - const char* modeToString(DeviceMode deviceMode); -}; - - -class SingleTouchInputMapper : public TouchInputMapper { -public: - explicit SingleTouchInputMapper(InputDevice* device); - virtual ~SingleTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, RawState* outState); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; -}; - - -class MultiTouchInputMapper : public TouchInputMapper { -public: - explicit MultiTouchInputMapper(InputDevice* device); - virtual ~MultiTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, RawState* outState); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; - - // Specifies the pointer id bits that are in use, and their associated tracking id. - BitSet32 mPointerIdBits; - int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; -}; - -class ExternalStylusInputMapper : public InputMapper { -public: - explicit ExternalStylusInputMapper(InputDevice* device); - virtual ~ExternalStylusInputMapper() = default; - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - virtual void sync(nsecs_t when); - -private: - SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; - RawAbsoluteAxisInfo mRawPressureAxis; - TouchButtonAccumulator mTouchButtonAccumulator; - - StylusState mStylusState; -}; - - -class JoystickInputMapper : public InputMapper { -public: - explicit JoystickInputMapper(InputDevice* device); - virtual ~JoystickInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(std::string& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -private: - struct Axis { - RawAbsoluteAxisInfo rawAxisInfo; - AxisInfo axisInfo; - - bool explicitlyMapped; // true if the axis was explicitly assigned an axis id - - float scale; // scale factor from raw to normalized values - float offset; // offset to add after scaling for normalization - float highScale; // scale factor from raw to normalized values of high split - float highOffset; // offset to add after scaling for normalization of high split - - float min; // normalized inclusive minimum - float max; // normalized inclusive maximum - float flat; // normalized flat region size - float fuzz; // normalized error tolerance - float resolution; // normalized resolution in units/mm - - float filter; // filter out small variations of this size - float currentValue; // current value - float newValue; // most recent value - float highCurrentValue; // current value of high split - float highNewValue; // most recent value of high split - - void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, - bool explicitlyMapped, float scale, float offset, - float highScale, float highOffset, - float min, float max, float flat, float fuzz, float resolution) { - this->rawAxisInfo = rawAxisInfo; - this->axisInfo = axisInfo; - this->explicitlyMapped = explicitlyMapped; - this->scale = scale; - this->offset = offset; - this->highScale = highScale; - this->highOffset = highOffset; - this->min = min; - this->max = max; - this->flat = flat; - this->fuzz = fuzz; - this->resolution = resolution; - this->filter = 0; - resetValue(); - } - - void resetValue() { - this->currentValue = 0; - this->newValue = 0; - this->highCurrentValue = 0; - this->highNewValue = 0; - } - }; - - // Axes indexed by raw ABS_* axis index. - KeyedVector<int32_t, Axis> mAxes; - - void sync(nsecs_t when, bool force); - - bool haveAxis(int32_t axisId); - void pruneAxes(bool ignoreExplicitlyMappedAxes); - bool filterAxes(bool force); - - static bool hasValueChangedSignificantly(float filter, - float newValue, float currentValue, float min, float max); - static bool hasMovedNearerToValueWithinFilteredRange(float filter, - float newValue, float currentValue, float thresholdValue); - - static bool isCenteredAxis(int32_t axis); - static int32_t getCompatAxis(int32_t axis); - - static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info); - static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, - float value); -}; - -} // namespace android - -#endif // _UI_INPUT_READER_H diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp new file mode 100644 index 0000000000..b8c3a808f1 --- /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 0000000000..99e2108dbf --- /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 0000000000..ef7f6509e4 --- /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"; + } +} + +DispatchEntry* Connection::findWaitQueueEntry(uint32_t seq) { + for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) { + if (entry->seq == seq) { + return entry; + } + } + return nullptr; +} + +} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h new file mode 100644 index 0000000000..ed4eebdff4 --- /dev/null +++ b/services/inputflinger/dispatcher/Connection.h @@ -0,0 +1,74 @@ +/* + * 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 "Queue.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. + Queue<DispatchEntry> outboundQueue; + + // Queue of events that have been published to the connection but that have not + // yet received a "finished" response from the application. + Queue<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; + + DispatchEntry* 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 0000000000..8d05640b38 --- /dev/null +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -0,0 +1,255 @@ +/* + * 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, 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), + 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, " + "pointers=[", + deviceId, source, displayId, motionActionToString(action).c_str(), + actionButton, flags, metaState, buttonState, + motionClassificationToString(classification), edgeFlags, xPrecision, + yPrecision); + + 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 0000000000..b904caf671 --- /dev/null +++ b/services/inputflinger/dispatcher/Entry.h @@ -0,0 +1,223 @@ +/* + * 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 { + +template <typename T> +struct Link { + T* next; + T* prev; + +protected: + inline Link() : next(nullptr), prev(nullptr) {} +}; + +struct EventEntry : Link<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; + 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, 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 : Link<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 void (InputDispatcher::*Command)(CommandEntry* commandEntry); + +class Connection; +struct CommandEntry : Link<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 0000000000..b2d0a26a37 --- /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 0000000000..311a0f11ef --- /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/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index c2ff4c9629..44100086c4 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -45,20 +45,22 @@ #include "InputDispatcher.h" +#include "Connection.h" + #include <errno.h> #include <inttypes.h> #include <limits.h> -#include <sstream> #include <stddef.h> #include <time.h> #include <unistd.h> +#include <sstream> #include <android-base/chrono_utils.h> #include <android-base/stringprintf.h> +#include <binder/Binder.h> #include <log/log.h> -#include <utils/Trace.h> #include <powermanager/PowerManager.h> -#include <binder/Binder.h> +#include <utils/Trace.h> #define INDENT " " #define INDENT2 " " @@ -67,7 +69,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. @@ -97,10 +99,6 @@ constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms; // 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,71 +107,23 @@ static inline const char* toString(bool value) { 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; + return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } static bool isValidKeyAction(int32_t action) { switch (action) { - case AKEY_EVENT_ACTION_DOWN: - case AKEY_EVENT_ACTION_UP: - return true; - default: - return false; + case AKEY_EVENT_ACTION_DOWN: + case AKEY_EVENT_ACTION_UP: + return true; + default: + return false; } } static bool validateKeyEvent(int32_t action) { - if (! isValidKeyAction(action)) { + if (!isValidKeyAction(action)) { ALOGE("Key event has invalid action code 0x%x", action); return false; } @@ -182,46 +132,46 @@ static bool validateKeyEvent(int32_t action) { static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_OUTSIDE: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - case AMOTION_EVENT_ACTION_HOVER_EXIT: - case AMOTION_EVENT_ACTION_SCROLL: - return true; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: { - int32_t index = getMotionEventActionPointerIndex(action); - return index >= 0 && index < pointerCount; - } - case AMOTION_EVENT_ACTION_BUTTON_PRESS: - case AMOTION_EVENT_ACTION_BUTTON_RELEASE: - return actionButton != 0; - default: - return false; + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_MOVE: + case AMOTION_EVENT_ACTION_OUTSIDE: + case AMOTION_EVENT_ACTION_HOVER_ENTER: + case AMOTION_EVENT_ACTION_HOVER_MOVE: + case AMOTION_EVENT_ACTION_HOVER_EXIT: + case AMOTION_EVENT_ACTION_SCROLL: + return true; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: { + int32_t index = getMotionEventActionPointerIndex(action); + return index >= 0 && index < pointerCount; + } + case AMOTION_EVENT_ACTION_BUTTON_PRESS: + case AMOTION_EVENT_ACTION_BUTTON_RELEASE: + return actionButton != 0; + default: + return false; } } static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount, - const PointerProperties* pointerProperties) { - if (! isValidMotionAction(action, actionButton, pointerCount)) { + const PointerProperties* pointerProperties) { + if (!isValidMotionAction(action, actionButton, pointerCount)) { ALOGE("Motion event has invalid action code 0x%x", action); return false; } if (pointerCount < 1 || pointerCount > MAX_POINTERS) { ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %d.", - pointerCount, MAX_POINTERS); + pointerCount, MAX_POINTERS); return false; } BitSet32 pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { int32_t id = pointerProperties[i].id; if (id < 0 || id > MAX_POINTER_ID) { - ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", - id, MAX_POINTER_ID); + ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id, + MAX_POINTER_ID); return false; } if (pointerIdBits.hasBit(id)) { @@ -253,23 +203,26 @@ static void dumpRegion(std::string& dump, const Region& region) { } } -template<typename T, typename U> +template <typename T, typename U> static T getValueByKey(std::unordered_map<U, T>& map, U key) { typename std::unordered_map<U, T>::const_iterator it = map.find(key); return it != map.end() ? it->second : T{}; } - // --- InputDispatcher --- -InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : - mPolicy(policy), - mPendingEvent(nullptr), mLastDropReason(DROP_REASON_NOT_DROPPED), - mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), - mNextUnblockedEvent(nullptr), - mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), - mFocusedDisplayId(ADISPLAY_ID_DEFAULT), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { +InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) + : mPolicy(policy), + mPendingEvent(nullptr), + mLastDropReason(DROP_REASON_NOT_DROPPED), + mAppSwitchSawKeyDown(false), + mAppSwitchDueTime(LONG_LONG_MAX), + mNextUnblockedEvent(nullptr), + mDispatchEnabled(false), + mDispatchFrozen(false), + mInputFilterEnabled(false), + mFocusedDisplayId(ADISPLAY_ID_DEFAULT), + mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); mReporter = createInputReporter(); @@ -345,7 +298,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { // Ready to start a new event. // If we don't already have a pending event, go grab one. - if (! mPendingEvent) { + if (!mPendingEvent) { if (mInboundQueue.isEmpty()) { if (isAppSwitchDue) { // The inbound queue is empty so the app switch key we were waiting @@ -400,63 +353,59 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { } switch (mPendingEvent->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: { - ConfigurationChangedEntry* typedEntry = - static_cast<ConfigurationChangedEntry*>(mPendingEvent); - done = dispatchConfigurationChangedLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped - break; - } - - case EventEntry::TYPE_DEVICE_RESET: { - DeviceResetEntry* typedEntry = - static_cast<DeviceResetEntry*>(mPendingEvent); - done = dispatchDeviceResetLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped - break; - } - - case EventEntry::TYPE_KEY: { - KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); - if (isAppSwitchDue) { - if (isAppSwitchKeyEvent(typedEntry)) { - resetPendingAppSwitchLocked(true); - isAppSwitchDue = false; - } else if (dropReason == DROP_REASON_NOT_DROPPED) { - dropReason = DROP_REASON_APP_SWITCH; - } - } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEvent(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; + case EventEntry::TYPE_CONFIGURATION_CHANGED: { + ConfigurationChangedEntry* typedEntry = + static_cast<ConfigurationChangedEntry*>(mPendingEvent); + done = dispatchConfigurationChangedLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped + break; } - done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); - break; - } - case EventEntry::TYPE_MOTION: { - MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); - if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { - dropReason = DROP_REASON_APP_SWITCH; + case EventEntry::TYPE_DEVICE_RESET: { + DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent); + done = dispatchDeviceResetLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped + break; } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEvent(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; + + case EventEntry::TYPE_KEY: { + KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); + if (isAppSwitchDue) { + if (isAppSwitchKeyEvent(typedEntry)) { + resetPendingAppSwitchLocked(true); + isAppSwitchDue = false; + } else if (dropReason == DROP_REASON_NOT_DROPPED) { + dropReason = DROP_REASON_APP_SWITCH; + } + } + if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; + } + done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); + break; } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; + + case EventEntry::TYPE_MOTION: { + MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); + if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { + dropReason = DROP_REASON_APP_SWITCH; + } + if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) { + dropReason = DROP_REASON_STALE; + } + if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { + dropReason = DROP_REASON_BLOCKED; + } + done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); + break; } - done = dispatchMotionLocked(currentTime, typedEntry, - &dropReason, nextWakeupTime); - break; - } - default: - ALOG_ASSERT(false); - break; + default: + ALOG_ASSERT(false); + break; } if (done) { @@ -466,7 +415,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { mLastDropReason = dropReason; releasePendingEventLocked(); - *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately + *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } } @@ -476,55 +425,56 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { traceInboundQueueLengthLocked(); switch (entry->type) { - case EventEntry::TYPE_KEY: { - // Optimize app switch latency. - // If the application takes too long to catch up then we drop all events preceding - // the app switch key. - KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); - if (isAppSwitchKeyEvent(keyEntry)) { - if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { - mAppSwitchSawKeyDown = true; - } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - if (mAppSwitchSawKeyDown) { + case EventEntry::TYPE_KEY: { + // Optimize app switch latency. + // If the application takes too long to catch up then we drop all events preceding + // the app switch key. + KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); + if (isAppSwitchKeyEvent(keyEntry)) { + if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { + mAppSwitchSawKeyDown = true; + } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { + if (mAppSwitchSawKeyDown) { #if DEBUG_APP_SWITCH - ALOGD("App switch is pending!"); + ALOGD("App switch is pending!"); #endif - mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; - mAppSwitchSawKeyDown = false; - needWake = true; + mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; + mAppSwitchSawKeyDown = false; + needWake = true; + } } } + break; } - break; - } - - case EventEntry::TYPE_MOTION: { - // Optimize case where the current application is unresponsive and the user - // decides to touch a window in a different application. - // If the application takes too long to catch up then we drop all events preceding - // the touch into the other window. - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN - && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY - && mInputTargetWaitApplicationToken != nullptr) { - int32_t displayId = motionEntry->displayId; - int32_t x = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); - if (touchedWindowHandle != nullptr - && touchedWindowHandle->getApplicationToken() - != mInputTargetWaitApplicationToken) { - // User touched a different application than the one we are waiting on. - // Flag the event, and start pruning the input queue. - mNextUnblockedEvent = motionEntry; - needWake = true; + + case EventEntry::TYPE_MOTION: { + // Optimize case where the current application is unresponsive and the user + // decides to touch a window in a different application. + // If the application takes too long to catch up then we drop all events preceding + // the touch into the other window. + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && + (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && + mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && + mInputTargetWaitApplicationToken != nullptr) { + int32_t displayId = motionEntry->displayId; + int32_t x = + int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); + int32_t y = + int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); + sp<InputWindowHandle> touchedWindowHandle = + findTouchedWindowAtLocked(displayId, x, y); + if (touchedWindowHandle != nullptr && + touchedWindowHandle->getApplicationToken() != + mInputTargetWaitApplicationToken) { + // User touched a different application than the one we are waiting on. + // Flag the event, and start pruning the input queue. + mNextUnblockedEvent = motionEntry; + needWake = true; + } } + break; } - break; - } } return needWake; @@ -538,8 +488,9 @@ void InputDispatcher::addRecentEventLocked(EventEntry* entry) { } } -sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, - int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) { +sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, + int32_t y, bool addOutsideTargets, + bool addPortalWindows) { // Traverse windows from front to back to find touched window. const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); for (const sp<InputWindowHandle>& windowHandle : windowHandles) { @@ -549,18 +500,19 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display if (windowInfo->visible) { if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; + bool isTouchModal = (flags & + (InputWindowInfo::FLAG_NOT_FOCUSABLE | + InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { int32_t portalToDisplayId = windowInfo->portalToDisplayId; - if (portalToDisplayId != ADISPLAY_ID_NONE - && portalToDisplayId != displayId) { + if (portalToDisplayId != ADISPLAY_ID_NONE && + portalToDisplayId != displayId) { if (addPortalWindows) { // For the monitoring channels of the display. mTempTouchState.addPortalWindow(windowHandle); } - return findTouchedWindowAtLocked( - portalToDisplayId, x, y, addOutsideTargets, addPortalWindows); + return findTouchedWindowAtLocked(portalToDisplayId, x, y, + addOutsideTargets, addPortalWindows); } // Found window. return windowHandle; @@ -568,8 +520,9 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display } if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { - mTempTouchState.addOrUpdateWindow( - windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0)); + mTempTouchState.addOrUpdateWindow(windowHandle, + InputTarget::FLAG_DISPATCH_AS_OUTSIDE, + BitSet32(0)); } } } @@ -577,7 +530,7 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display 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; @@ -586,14 +539,15 @@ std::vector<InputDispatcher::TouchedMonitor> InputDispatcher::findTouchedGesture for (const sp<InputWindowHandle>& portalWindow : portalWindows) { const InputWindowInfo* windowInfo = portalWindow->getInfo(); monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId); - addGestureMonitors(monitors, touchedMonitors, - -windowInfo->frameLeft, -windowInfo->frameTop); + addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft, + -windowInfo->frameTop); } return touchedMonitors; } void InputDispatcher::addGestureMonitors(const std::vector<Monitor>& monitors, - std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset, float yOffset) { + std::vector<TouchedMonitor>& outTouchedMonitors, + float xOffset, float yOffset) { if (monitors.empty()) { return; } @@ -606,68 +560,66 @@ void InputDispatcher::addGestureMonitors(const std::vector<Monitor>& monitors, void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { const char* reason; switch (dropReason) { - case DROP_REASON_POLICY: + case DROP_REASON_POLICY: #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("Dropped event because policy consumed it."); + ALOGD("Dropped event because policy consumed it."); #endif - reason = "inbound event was dropped because the policy consumed it"; - break; - case DROP_REASON_DISABLED: - if (mLastDropReason != DROP_REASON_DISABLED) { - ALOGI("Dropped event because input dispatch is disabled."); - } - reason = "inbound event was dropped because input dispatch is disabled"; - break; - case DROP_REASON_APP_SWITCH: - ALOGI("Dropped event because of pending overdue app switch."); - reason = "inbound event was dropped because of pending overdue app switch"; - break; - case DROP_REASON_BLOCKED: - ALOGI("Dropped event because the current application is not responding and the user " - "has started interacting with a different application."); - reason = "inbound event was dropped because the current application is not responding " - "and the user has started interacting with a different application"; - break; - case DROP_REASON_STALE: - ALOGI("Dropped event because it is stale."); - reason = "inbound event was dropped because it is stale"; - break; - default: - ALOG_ASSERT(false); - return; + reason = "inbound event was dropped because the policy consumed it"; + break; + case DROP_REASON_DISABLED: + if (mLastDropReason != DROP_REASON_DISABLED) { + ALOGI("Dropped event because input dispatch is disabled."); + } + reason = "inbound event was dropped because input dispatch is disabled"; + break; + case DROP_REASON_APP_SWITCH: + ALOGI("Dropped event because of pending overdue app switch."); + reason = "inbound event was dropped because of pending overdue app switch"; + break; + case DROP_REASON_BLOCKED: + ALOGI("Dropped event because the current application is not responding and the user " + "has started interacting with a different application."); + reason = "inbound event was dropped because the current application is not responding " + "and the user has started interacting with a different application"; + break; + case DROP_REASON_STALE: + ALOGI("Dropped event because it is stale."); + reason = "inbound event was dropped because it is stale"; + break; + default: + ALOG_ASSERT(false); + return; } switch (entry->type) { - case EventEntry::TYPE_KEY: { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - break; - } - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } else { + case EventEntry::TYPE_KEY: { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); + break; + } + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); + if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { + CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); + synthesizeCancelationEventsForAllConnectionsLocked(options); + } else { + CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); + synthesizeCancelationEventsForAllConnectionsLocked(options); + } + break; } - break; - } } } static bool isAppSwitchKeyCode(int32_t keyCode) { - return keyCode == AKEYCODE_HOME - || keyCode == AKEYCODE_ENDCALL - || keyCode == AKEYCODE_APP_SWITCH; + return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL || + keyCode == AKEYCODE_APP_SWITCH; } bool InputDispatcher::isAppSwitchKeyEvent(KeyEntry* keyEntry) { - return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) - && isAppSwitchKeyCode(keyEntry->keyCode) - && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) - && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); + return !(keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry->keyCode) && + (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) && + (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); } bool InputDispatcher::isAppSwitchPendingLocked() { @@ -707,18 +659,18 @@ bool InputDispatcher::runCommandsLockedInterruptible() { commandEntry->connection.clear(); delete commandEntry; - } while (! mCommandQueue.isEmpty()); + } while (!mCommandQueue.isEmpty()); return true; } -InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { +CommandEntry* InputDispatcher::postCommandLocked(Command command) { CommandEntry* commandEntry = new CommandEntry(command); mCommandQueue.enqueueAtTail(commandEntry); return commandEntry; } void InputDispatcher::drainInboundQueueLocked() { - while (! mInboundQueue.isEmpty()) { + while (!mInboundQueue.isEmpty()) { EventEntry* entry = mInboundQueue.dequeueAtHead(); releaseInboundEventLocked(entry); } @@ -755,7 +707,7 @@ void InputDispatcher::resetKeyRepeatLocked() { } } -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. @@ -767,10 +719,11 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t cu entry->policyFlags = policyFlags; entry->repeatCount += 1; } else { - KeyEntry* newEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, - entry->deviceId, entry->source, entry->displayId, policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, - entry->metaState, entry->repeatCount + 1, entry->downTime); + KeyEntry* newEntry = + new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, entry->deviceId, + entry->source, entry->displayId, policyFlags, entry->action, + entry->flags, entry->keyCode, entry->scanCode, entry->metaState, + entry->repeatCount + 1, entry->downTime); mKeyRepeatState.lastKeyEntry = newEntry; entry->release(); @@ -787,8 +740,8 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t cu return entry; } -bool InputDispatcher::dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry) { +bool InputDispatcher::dispatchConfigurationChangedLocked(nsecs_t currentTime, + ConfigurationChangedEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime); #endif @@ -797,36 +750,33 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( resetKeyRepeatLocked(); // Enqueue a command to run outside the lock to tell the policy that the configuration changed. - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyConfigurationChangedLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible); commandEntry->eventTime = entry->eventTime; return true; } -bool InputDispatcher::dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry) { +bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime, - entry->deviceId); + entry->deviceId); #endif - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "device was reset"); + CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset"); options.deviceId = entry->deviceId; synthesizeCancelationEventsForAllConnectionsLocked(options); return true; } bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) { + DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. - if (! entry->dispatchInProgress) { - if (entry->repeatCount == 0 - && entry->action == AKEY_EVENT_ACTION_DOWN - && (entry->policyFlags & POLICY_FLAG_TRUSTED) - && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { - if (mKeyRepeatState.lastKeyEntry - && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { + if (!entry->dispatchInProgress) { + if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN && + (entry->policyFlags & POLICY_FLAG_TRUSTED) && + (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { + if (mKeyRepeatState.lastKeyEntry && + mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { // We have seen two identical key downs in a row which indicates that the device // driver is automatically generating key repeats itself. We take note of the // repeat here, but we disable our own next key repeat timer since it is clear that @@ -841,7 +791,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, } mKeyRepeatState.lastKeyEntry = entry; entry->refCount += 1; - } else if (! entry->syntheticRepeat) { + } else if (!entry->syntheticRepeat) { resetKeyRepeatLocked(); } @@ -872,12 +822,11 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); + &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); sp<InputWindowHandle> focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { - commandEntry->inputChannel = - getInputChannelLocked(focusedWindowHandle->getToken()); + commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken()); } commandEntry->keyEntry = entry; entry->refCount += 1; @@ -893,16 +842,17 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResult(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); + setInjectionResult(entry, + *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED + : INPUT_EVENT_INJECTION_FAILED); mReporter->reportDroppedKey(entry->sequenceNum); return true; } // Identify targets. std::vector<InputTarget> inputTargets; - int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); + int32_t injectionResult = + findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } @@ -923,20 +873,19 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", " - "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, " - "metaState=0x%x, repeatCount=%d, downTime=%" PRId64, - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->repeatCount, entry->downTime); + "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, " + "metaState=0x%x, repeatCount=%d, downTime=%" PRId64, + prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId, + entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, + entry->metaState, entry->repeatCount, entry->downTime); #endif } -bool InputDispatcher::dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { +bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, + DropReason* dropReason, nsecs_t* nextWakeupTime) { ATRACE_CALL(); // Preprocessing. - if (! entry->dispatchInProgress) { + if (!entry->dispatchInProgress) { entry->dispatchInProgress = true; logOutboundMotionDetails("dispatchMotion - ", entry); @@ -944,8 +893,9 @@ bool InputDispatcher::dispatchMotionLocked( // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResult(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); + setInjectionResult(entry, + *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED + : INPUT_EVENT_INJECTION_FAILED); return true; } @@ -958,12 +908,13 @@ bool InputDispatcher::dispatchMotionLocked( int32_t injectionResult; if (isPointerEvent) { // Pointer event. (eg. touchscreen) - injectionResult = findTouchedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime, &conflictingPointerActions); + injectionResult = + findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, + &conflictingPointerActions); } else { // Non touch event. (eg. trackball) - injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); + injectionResult = + findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); } if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; @@ -972,9 +923,9 @@ bool InputDispatcher::dispatchMotionLocked( setInjectionResult(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) { - CancelationOptions::Mode mode(isPointerEvent ? - CancelationOptions::CANCEL_POINTER_EVENTS : - CancelationOptions::CANCEL_NON_POINTER_EVENTS); + CancelationOptions::Mode mode(isPointerEvent + ? CancelationOptions::CANCEL_POINTER_EVENTS + : CancelationOptions::CANCEL_NON_POINTER_EVENTS); CancelationOptions options(mode, "input event injection failed"); synthesizeCancelationEventsForMonitorsLocked(options); } @@ -994,7 +945,7 @@ bool InputDispatcher::dispatchMotionLocked( for (size_t i = 0; i < state.portalWindows.size(); i++) { const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo(); addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, - -windowInfo->frameLeft, -windowInfo->frameTop); + -windowInfo->frameLeft, -windowInfo->frameTop); } } } @@ -1003,50 +954,46 @@ bool InputDispatcher::dispatchMotionLocked( // Dispatch the motion. if (conflictingPointerActions) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "conflicting pointer actions"); + "conflicting pointer actions"); synthesizeCancelationEventsForAllConnectionsLocked(options); } dispatchEventLocked(currentTime, entry, inputTargets); return true; } - void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, " - "metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags, - entry->action, entry->actionButton, entry->flags, - entry->metaState, entry->buttonState, - entry->edgeFlags, entry->xPrecision, entry->yPrecision, - entry->downTime); + ", policyFlags=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, " + "metaState=0x%x, buttonState=0x%x," + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, + prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId, + entry->policyFlags, entry->action, entry->actionButton, entry->flags, entry->metaState, + entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, + entry->downTime); for (uint32_t i = 0; i < entry->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, entry->pointerProperties[i].id, - entry->pointerProperties[i].toolType, - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + "x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " + "orientation=%f", + i, entry->pointerProperties[i].id, entry->pointerProperties[i].toolType, + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif } -void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, - EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) { +void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, + const std::vector<InputTarget>& inputTargets) { ATRACE_CALL(); #if DEBUG_DISPATCH_CYCLE ALOGD("dispatchEventToCurrentInputTargets"); @@ -1064,18 +1011,17 @@ void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, } else { #if DEBUG_FOCUS ALOGD("Dropping event delivery to target with channel '%s' because it " - "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().c_str()); + "is no longer registered with the input dispatcher.", + inputTarget.inputChannel->getName().c_str()); #endif } } } -int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, - const EventEntry* entry, +int32_t InputDispatcher::handleTargetsNotReadyLocked( + nsecs_t currentTime, const EventEntry* entry, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t* nextWakeupTime, const char* reason) { + const sp<InputWindowHandle>& windowHandle, nsecs_t* nextWakeupTime, const char* reason) { if (applicationHandle == nullptr && windowHandle == nullptr) { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { #if DEBUG_FOCUS @@ -1091,15 +1037,14 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { #if DEBUG_FOCUS ALOGD("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), - reason); + getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason); #endif nsecs_t timeout; if (windowHandle != nullptr) { timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else if (applicationHandle != nullptr) { - timeout = applicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT); + timeout = + applicationHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else { timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; } @@ -1124,8 +1069,8 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, } if (currentTime >= mInputTargetWaitTimeoutTime) { - onANRLocked(currentTime, applicationHandle, windowHandle, - entry->eventTime, mInputTargetWaitStartTime, reason); + onANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime, + mInputTargetWaitStartTime, reason); // Force poll loop to wake up immediately on next iteration once we get the // ANR response back from the policy. @@ -1147,8 +1092,8 @@ void InputDispatcher::removeWindowByTokenLocked(const sp<IBinder>& token) { } } -void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp<InputChannel>& inputChannel) { +void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked( + nsecs_t newTimeout, const sp<InputChannel>& inputChannel) { if (newTimeout > 0) { // Extend the timeout. mInputTargetWaitTimeoutTime = now() + newTimeout; @@ -1169,7 +1114,7 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout if (connection->status == Connection::STATUS_NORMAL) { CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "application not responding"); + "application not responding"); synthesizeCancelationEventsForConnectionLocked(connection, options); } } @@ -1177,8 +1122,7 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout } } -nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( - nsecs_t currentTime) { +nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) { if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { return currentTime - mInputTargetWaitStartTime; } @@ -1187,7 +1131,7 @@ nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( void InputDispatcher::resetANRTimeoutsLocked() { #if DEBUG_FOCUS - ALOGD("Resetting ANR timeouts."); + ALOGD("Resetting ANR timeouts."); #endif // Reset input target wait timeout. @@ -1203,26 +1147,28 @@ void InputDispatcher::resetANRTimeoutsLocked() { int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) { int32_t displayId; switch (entry->type) { - case EventEntry::TYPE_KEY: { - const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry); - displayId = typedEntry->displayId; - break; - } - case EventEntry::TYPE_MOTION: { - const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry); - displayId = typedEntry->displayId; - break; - } - default: { - ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type); - return ADISPLAY_ID_NONE; - } + case EventEntry::TYPE_KEY: { + const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry); + displayId = typedEntry->displayId; + break; + } + case EventEntry::TYPE_MOTION: { + const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry); + displayId = typedEntry->displayId; + break; + } + default: { + ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type); + return ADISPLAY_ID_NONE; + } } return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId; } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, - const EventEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { + const EventEntry* entry, + std::vector<InputTarget>& inputTargets, + nsecs_t* nextWakeupTime) { int32_t injectionResult; std::string reason; @@ -1236,16 +1182,20 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, // then drop the event. if (focusedWindowHandle == nullptr) { if (focusedApplicationHandle != nullptr) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - focusedApplicationHandle, nullptr, nextWakeupTime, - "Waiting because no window has focus but there is a " - "focused application that may eventually add a window " - "when it finishes starting up."); + injectionResult = + handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, + nullptr, nextWakeupTime, + "Waiting because no window has focus but there is " + "a " + "focused application that may eventually add a " + "window " + "when it finishes starting up."); goto Unresponsive; } ALOGI("Dropping event because there is no focused window or focused application in display " - "%" PRId32 ".", displayId); + "%" PRId32 ".", + displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1257,19 +1207,19 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, } // Check whether the window is ready for more input. - reason = checkWindowReadyForMoreInputLocked(currentTime, - focusedWindowHandle, entry, "focused"); + reason = checkWindowReadyForMoreInputLocked(currentTime, focusedWindowHandle, entry, "focused"); if (!reason.empty()) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str()); + injectionResult = + handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, + focusedWindowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; addWindowTargetLocked(focusedWindowHandle, - InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), - inputTargets); + InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, + BitSet32(0), inputTargets); // Done. Failed: @@ -1278,15 +1228,17 @@ Unresponsive: updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findFocusedWindow finished: injectionResult=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, timeSpentWaitingForApplication / 1000000.0); + "timeSpentWaitingForApplication=%0.1fms", + injectionResult, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, - const MotionEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions) { + const MotionEntry* entry, + std::vector<InputTarget>& inputTargets, + nsecs_t* nextWakeupTime, + bool* outConflictingPointerActions) { ATRACE_CALL(); enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, @@ -1316,23 +1268,22 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } bool isSplit = mTempTouchState.split; - bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 - && (mTempTouchState.deviceId != entry->deviceId - || mTempTouchState.source != entry->source - || mTempTouchState.displayId != displayId); - bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); - bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN - || maskedAction == AMOTION_EVENT_ACTION_SCROLL - || isHoverAction); + bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 && + (mTempTouchState.deviceId != entry->deviceId || + mTempTouchState.source != entry->source || mTempTouchState.displayId != displayId); + bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || + maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || + maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); + bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN || + maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction); bool wrongDevice = false; if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) { #if DEBUG_FOCUS ALOGD("Dropping event because a pointer for a different device is already down " - "in display %" PRId32, displayId); + "in display %" PRId32, + displayId); #endif // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_FAILED; @@ -1349,7 +1300,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) { #if DEBUG_FOCUS ALOGI("Dropping move event because a pointer for a different device is already active " - "in display %" PRId32, displayId); + "in display %" PRId32, + displayId); #endif // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; @@ -1362,21 +1314,20 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); + int32_t x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X)); + int32_t y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)); bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; - sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked( - displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/); + sp<InputWindowHandle> newTouchedWindowHandle = + findTouchedWindowAtLocked(displayId, x, y, isDown /*addOutsideTargets*/, + true /*addPortalWindows*/); std::vector<TouchedMonitor> newGestureMonitors = isDown ? findTouchedGestureMonitorsLocked(displayId, mTempTouchState.portalWindows) : std::vector<TouchedMonitor>{}; // Figure out whether splitting will be allowed for this window. - if (newTouchedWindowHandle != nullptr - && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { + if (newTouchedWindowHandle != nullptr && + newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { // New window supports splitting. isSplit = true; } else if (isSplit) { @@ -1393,7 +1344,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) { ALOGI("Dropping event because there is no touchable window or gesture monitor at " - "(%d, %d) in display %" PRId32 ".", x, y, displayId); + "(%d, %d) in display %" PRId32 ".", + x, y, displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1431,19 +1383,19 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ // If the pointer is not currently down, then ignore the event. - if (! mTempTouchState.down) { + if (!mTempTouchState.down) { #if DEBUG_FOCUS ALOGD("Dropping event because the pointer is not down or we previously " - "dropped the pointer down event in display %" PRId32, displayId); + "dropped the pointer down event in display %" PRId32, + displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Check whether touches should slip outside of the current foreground window. - if (maskedAction == AMOTION_EVENT_ACTION_MOVE - && entry->pointerCount == 1 - && mTempTouchState.isSlippery()) { + if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry->pointerCount == 1 && + mTempTouchState.isSlippery()) { int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); @@ -1451,26 +1403,25 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, mTempTouchState.getFirstForegroundWindowHandle(); sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); - if (oldTouchedWindowHandle != newTouchedWindowHandle - && oldTouchedWindowHandle != nullptr - && newTouchedWindowHandle != nullptr) { + if (oldTouchedWindowHandle != newTouchedWindowHandle && + oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32, - oldTouchedWindowHandle->getName().c_str(), - newTouchedWindowHandle->getName().c_str(), - displayId); + oldTouchedWindowHandle->getName().c_str(), + newTouchedWindowHandle->getName().c_str(), displayId); #endif // Make a slippery exit from the old window. mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, + BitSet32(0)); // Make a slippery entrance into the new window. if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { isSplit = true; } - int32_t targetFlags = InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; + int32_t targetFlags = + InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } @@ -1492,20 +1443,22 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (mLastHoverWindowHandle != nullptr) { #if DEBUG_HOVER ALOGD("Sending hover exit event to window %s.", - mLastHoverWindowHandle->getName().c_str()); + mLastHoverWindowHandle->getName().c_str()); #endif mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, + BitSet32(0)); } // Let the new window know that the hover sequence is starting. if (newHoverWindowHandle != nullptr) { #if DEBUG_HOVER ALOGD("Sending hover enter event to window %s.", - newHoverWindowHandle->getName().c_str()); + newHoverWindowHandle->getName().c_str()); #endif mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); + InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, + BitSet32(0)); } } @@ -1516,8 +1469,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; - if (! checkInjectionPermission(touchedWindow.windowHandle, - entry->injectionState)) { + if (!checkInjectionPermission(touchedWindow.windowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; goto Failed; @@ -1527,8 +1479,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool hasGestureMonitor = !mTempTouchState.gestureMonitors.empty(); if (!haveForegroundWindow && !hasGestureMonitor) { #if DEBUG_FOCUS - ALOGD("Dropping event because there is no touched foreground window in display %" - PRId32 " or gesture monitor to receive it.", displayId); + ALOGD("Dropping event because there is no touched foreground window in display %" PRId32 + " or gesture monitor to receive it.", + displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; @@ -1550,7 +1503,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { mTempTouchState.addOrUpdateWindow(inputWindowHandle, - InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); + InputTarget::FLAG_ZERO_COORDS, + BitSet32(0)); } } } @@ -1561,11 +1515,13 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // Check whether the window is ready for more input. - std::string reason = checkWindowReadyForMoreInputLocked(currentTime, - touchedWindow.windowHandle, entry, "touched"); + std::string reason = + checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, + entry, "touched"); if (!reason.empty()) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - nullptr, touchedWindow.windowHandle, nextWakeupTime, reason.c_str()); + injectionResult = handleTargetsNotReadyLocked(currentTime, entry, nullptr, + touchedWindow.windowHandle, + nextWakeupTime, reason.c_str()); goto Unresponsive; } } @@ -1585,14 +1541,15 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, getWindowHandlesLocked(displayId); for (const sp<InputWindowHandle>& windowHandle : windowHandles) { const InputWindowInfo* info = windowHandle->getInfo(); - if (info->displayId == displayId - && windowHandle->getInfo()->layoutParamsType - == InputWindowInfo::TYPE_WALLPAPER) { - mTempTouchState.addOrUpdateWindow(windowHandle, - InputTarget::FLAG_WINDOW_IS_OBSCURED - | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED - | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); + if (info->displayId == displayId && + windowHandle->getInfo()->layoutParamsType == InputWindowInfo::TYPE_WALLPAPER) { + mTempTouchState + .addOrUpdateWindow(windowHandle, + InputTarget::FLAG_WINDOW_IS_OBSCURED | + InputTarget:: + FLAG_WINDOW_IS_PARTIALLY_OBSCURED | + InputTarget::FLAG_DISPATCH_AS_IS, + BitSet32(0)); } } } @@ -1603,12 +1560,12 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, inputTargets); + touchedWindow.pointerIds, inputTargets); } for (const TouchedMonitor& touchedMonitor : mTempTouchState.gestureMonitors) { addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset, - touchedMonitor.yOffset, inputTargets); + touchedMonitor.yOffset, inputTargets); } // Drop the outside or hover touch windows since we will not care about them @@ -1644,14 +1601,14 @@ Failed: *outConflictingPointerActions = true; } mTempTouchState.reset(); - if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { + if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || + maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { mTempTouchState.deviceId = entry->deviceId; mTempTouchState.source = entry->source; mTempTouchState.displayId = displayId; } - } else if (maskedAction == AMOTION_EVENT_ACTION_UP - || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { + } else if (maskedAction == AMOTION_EVENT_ACTION_UP || + maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. mTempTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { @@ -1668,7 +1625,7 @@ Failed: int32_t pointerIndex = getMotionEventActionPointerIndex(action); uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - for (size_t i = 0; i < mTempTouchState.windows.size(); ) { + for (size_t i = 0; i < mTempTouchState.windows.size();) { TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { touchedWindow.pointerIds.clearBit(pointerId); @@ -1713,14 +1670,15 @@ Unresponsive: updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); + "timeSpentWaitingForApplication=%0.1fms", + injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) { + int32_t targetFlags, BitSet32 pointerIds, + std::vector<InputTarget>& inputTargets) { sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken()); if (inputChannel == nullptr) { ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str()); @@ -1731,8 +1689,8 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH InputTarget target; target.inputChannel = inputChannel; target.flags = targetFlags; - target.xOffset = - windowInfo->frameLeft; - target.yOffset = - windowInfo->frameTop; + target.xOffset = -windowInfo->frameLeft; + target.yOffset = -windowInfo->frameTop; target.globalScaleFactor = windowInfo->globalScaleFactor; target.windowXScale = windowInfo->windowXScale; target.windowYScale = windowInfo->windowYScale; @@ -1741,8 +1699,8 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH } void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, - int32_t displayId, float xOffset, float yOffset) { - + int32_t displayId, float xOffset, + float yOffset) { std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it = mGlobalMonitorsByDisplay.find(displayId); @@ -1754,8 +1712,9 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& } } -void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, - float xOffset, float yOffset, std::vector<InputTarget>& inputTargets) { +void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset, + float yOffset, + std::vector<InputTarget>& inputTargets) { InputTarget target; target.inputChannel = monitor.inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; @@ -1767,28 +1726,27 @@ void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, } bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, - const InjectionState* injectionState) { - if (injectionState - && (windowHandle == nullptr - || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) - && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { + const InjectionState* injectionState) { + if (injectionState && + (windowHandle == nullptr || + windowHandle->getInfo()->ownerUid != injectionState->injectorUid) && + !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { if (windowHandle != nullptr) { ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " - "owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - windowHandle->getName().c_str(), - windowHandle->getInfo()->ownerUid); + "owned by uid %d", + injectionState->injectorPid, injectionState->injectorUid, + windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid); } else { ALOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); + injectionState->injectorPid, injectionState->injectorUid); } return false; } return true; } -bool InputDispatcher::isWindowObscuredAtPointLocked( - const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const { +bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, + int32_t x, int32_t y) const { int32_t displayId = windowHandle->getInfo()->displayId; const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); for (const sp<InputWindowHandle>& otherHandle : windowHandles) { @@ -1797,16 +1755,14 @@ bool InputDispatcher::isWindowObscuredAtPointLocked( } const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId - && otherInfo->visible && !otherInfo->isTrustedOverlay() - && otherInfo->frameContainsPoint(x, y)) { + if (otherInfo->displayId == displayId && otherInfo->visible && + !otherInfo->isTrustedOverlay() && otherInfo->frameContainsPoint(x, y)) { return true; } } return false; } - bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const { int32_t displayId = windowHandle->getInfo()->displayId; const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); @@ -1817,45 +1773,47 @@ bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& window } const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId - && otherInfo->visible && !otherInfo->isTrustedOverlay() - && otherInfo->overlaps(windowInfo)) { + if (otherInfo->displayId == displayId && otherInfo->visible && + !otherInfo->isTrustedOverlay() && otherInfo->overlaps(windowInfo)) { return true; } } return false; } -std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, - const char* targetType) { +std::string InputDispatcher::checkWindowReadyForMoreInputLocked( + nsecs_t currentTime, const sp<InputWindowHandle>& windowHandle, + const EventEntry* eventEntry, const char* targetType) { // If the window is paused then keep waiting. if (windowHandle->getInfo()->paused) { return StringPrintf("Waiting because the %s window is paused.", targetType); } // If the window's connection is not registered then keep waiting. - ssize_t connectionIndex = getConnectionIndexLocked( - getInputChannelLocked(windowHandle->getToken())); + ssize_t connectionIndex = + getConnectionIndexLocked(getInputChannelLocked(windowHandle->getToken())); if (connectionIndex < 0) { return StringPrintf("Waiting because the %s window's input channel is not " - "registered with the input dispatcher. The window may be in the process " - "of being removed.", targetType); + "registered with the input dispatcher. The window may be in the " + "process " + "of being removed.", + targetType); } // If the connection is dead then keep waiting. sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->status != Connection::STATUS_NORMAL) { return StringPrintf("Waiting because the %s window's input connection is %s." - "The window may be in the process of being removed.", targetType, - connection->getStatusLabel()); + "The window may be in the process of being removed.", + targetType, connection->getStatusLabel()); } // If the connection is backed up then keep waiting. if (connection->inputPublisherBlocked) { return StringPrintf("Waiting because the %s window's input channel is full. " - "Outbound queue length: %d. Wait queue length: %d.", - targetType, connection->outboundQueue.count(), connection->waitQueue.count()); + "Outbound queue length: %d. Wait queue length: %d.", + targetType, connection->outboundQueue.count(), + connection->waitQueue.count()); } // Ensure that the dispatch queues aren't too far backed up for this event. @@ -1873,9 +1831,11 @@ std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentT // prior input events. if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) { return StringPrintf("Waiting to send key event because the %s window has not " - "finished processing all of the input events that were previously " - "delivered to it. Outbound queue length: %d. Wait queue length: %d.", - targetType, connection->outboundQueue.count(), connection->waitQueue.count()); + "finished processing all of the input events that were previously " + "delivered to it. Outbound queue length: %d. Wait queue length: " + "%d.", + targetType, connection->outboundQueue.count(), + connection->waitQueue.count()); } } else { // Touch events can always be sent to a window immediately because the user intended @@ -1893,15 +1853,17 @@ std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentT // The one case where we pause input event delivery is when the wait queue is piling // up with lots of events because the application is not responding. // This condition ensures that ANRs are detected reliably. - if (!connection->waitQueue.isEmpty() - && currentTime >= connection->waitQueue.head->deliveryTime - + STREAM_AHEAD_EVENT_TIMEOUT) { + if (!connection->waitQueue.isEmpty() && + currentTime >= connection->waitQueue.head->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) { return StringPrintf("Waiting to send non-key event because the %s window has not " - "finished processing certain input events that were delivered to it over " - "%0.1fms ago. Wait queue length: %d. Wait queue head age: %0.1fms.", - targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f, - connection->waitQueue.count(), - (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f); + "finished processing certain input events that were delivered to " + "it over " + "%0.1fms ago. Wait queue length: %d. Wait queue head age: " + "%0.1fms.", + targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f, + connection->waitQueue.count(), + (currentTime - connection->waitQueue.head->deliveryTime) * + 0.000001f); } } return ""; @@ -1942,50 +1904,50 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { int32_t eventType = USER_ACTIVITY_EVENT_OTHER; switch (eventEntry->type) { - case EventEntry::TYPE_MOTION: { - const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); - if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { - return; - } + case EventEntry::TYPE_MOTION: { + const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); + if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { + return; + } - if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { - eventType = USER_ACTIVITY_EVENT_TOUCH; + if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { + eventType = USER_ACTIVITY_EVENT_TOUCH; + } + break; } - break; - } - case EventEntry::TYPE_KEY: { - const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry); - if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { - return; + case EventEntry::TYPE_KEY: { + const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry); + if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { + return; + } + eventType = USER_ACTIVITY_EVENT_BUTTON; + break; } - eventType = USER_ACTIVITY_EVENT_BUTTON; - break; - } } - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doPokeUserActivityLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible); commandEntry->eventTime = eventEntry->eventTime; commandEntry->userActivityEventType = eventType; } void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { + const sp<Connection>& connection, + EventEntry* eventEntry, + const InputTarget* inputTarget) { if (ATRACE_ENABLED()) { - std::string message = StringPrintf( - "prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", - connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + std::string message = + StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", + connection->getInputChannelName().c_str(), eventEntry->sequenceNum); ATRACE_NAME(message.c_str()); } #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " - "xOffset=%f, yOffset=%f, globalScaleFactor=%f, " - "windowScaleFactor=(%f, %f), pointerIds=0x%x", - connection->getInputChannelName().c_str(), inputTarget->flags, - inputTarget->xOffset, inputTarget->yOffset, - inputTarget->globalScaleFactor, - inputTarget->windowXScale, inputTarget->windowYScale, - inputTarget->pointerIds.value); + "xOffset=%f, yOffset=%f, globalScaleFactor=%f, " + "windowScaleFactor=(%f, %f), pointerIds=0x%x", + connection->getInputChannelName().c_str(), inputTarget->flags, inputTarget->xOffset, + inputTarget->yOffset, inputTarget->globalScaleFactor, inputTarget->windowXScale, + inputTarget->windowYScale, inputTarget->pointerIds.value); #endif // Skip this event if the connection status is not normal. @@ -1993,7 +1955,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, if (connection->status != Connection::STATUS_NORMAL) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Dropping event because the channel status is %s", - connection->getInputChannelName().c_str(), connection->getStatusLabel()); + connection->getInputChannelName().c_str(), connection->getStatusLabel()); #endif return; } @@ -2004,18 +1966,16 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry); if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { - MotionEntry* splitMotionEntry = splitMotionEvent( - originalMotionEntry, inputTarget->pointerIds); + MotionEntry* splitMotionEntry = + splitMotionEvent(originalMotionEntry, inputTarget->pointerIds); if (!splitMotionEntry) { return; // split event was dropped } #if DEBUG_FOCUS - ALOGD("channel '%s' ~ Split motion event.", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ Split motion event.", connection->getInputChannelName().c_str()); logOutboundMotionDetails(" ", splitMotionEntry); #endif - enqueueDispatchEntriesLocked(currentTime, connection, - splitMotionEntry, inputTarget); + enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); splitMotionEntry->release(); return; } @@ -2026,11 +1986,14 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { + const sp<Connection>& connection, + EventEntry* eventEntry, + const InputTarget* inputTarget) { if (ATRACE_ENABLED()) { - std::string message = StringPrintf( - "enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")", - connection->getInputChannelName().c_str(), eventEntry->sequenceNum); + std::string message = + StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32 + ")", + connection->getInputChannelName().c_str(), eventEntry->sequenceNum); ATRACE_NAME(message.c_str()); } @@ -2038,17 +2001,17 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); + InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_OUTSIDE); + InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); + InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_IS); + InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.isEmpty()) { @@ -2056,14 +2019,14 @@ void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, } } -void InputDispatcher::enqueueDispatchEntryLocked( - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, - int32_t dispatchMode) { +void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection, + EventEntry* eventEntry, + const InputTarget* inputTarget, + int32_t dispatchMode) { if (ATRACE_ENABLED()) { - std::string message = StringPrintf( - "enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)", - connection->getInputChannelName().c_str(), - dispatchModeToString(dispatchMode).c_str()); + std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)", + connection->getInputChannelName().c_str(), + dispatchModeToString(dispatchMode).c_str()); ATRACE_NAME(message.c_str()); } int32_t inputTargetFlags = inputTarget->flags; @@ -2074,78 +2037,81 @@ void InputDispatcher::enqueueDispatchEntryLocked( // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. - DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref - inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->globalScaleFactor, inputTarget->windowXScale, - inputTarget->windowYScale); + DispatchEntry* dispatchEntry = + new DispatchEntry(eventEntry, // increments ref + inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, + inputTarget->globalScaleFactor, inputTarget->windowXScale, + inputTarget->windowYScale); // Apply target flags and update the connection's input state. switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - dispatchEntry->resolvedAction = keyEntry->action; - dispatchEntry->resolvedFlags = keyEntry->flags; + case EventEntry::TYPE_KEY: { + KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); + dispatchEntry->resolvedAction = keyEntry->action; + dispatchEntry->resolvedFlags = keyEntry->flags; - if (!connection->inputState.trackKey(keyEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { + if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction, + dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", + connection->getInputChannelName().c_str()); #endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; - } else { - dispatchEntry->resolvedAction = motionEntry->action; + delete dispatchEntry; + return; // skip the inconsistent event + } + break; } - if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - && !connection->inputState.isHovering( - motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) { + + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); + if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; + } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; + } else { + dispatchEntry->resolvedAction = motionEntry->action; + } + if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE && + !connection->inputState.isHovering(motionEntry->deviceId, motionEntry->source, + motionEntry->displayId)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter " + "event", + connection->getInputChannelName().c_str()); #endif - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } + dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; + } - dispatchEntry->resolvedFlags = motionEntry->flags; - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; - } - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; - } + dispatchEntry->resolvedFlags = motionEntry->flags; + if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { + dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; + } + if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { + dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + } - if (!connection->inputState.trackMotion(motionEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { + if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction, + dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion " + "event", + connection->getInputChannelName().c_str()); #endif - delete dispatchEntry; - return; // skip the inconsistent event - } + delete dispatchEntry; + return; // skip the inconsistent event + } - dispatchPointerDownOutsideFocus(motionEntry->source, - dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken()); + dispatchPointerDownOutsideFocus(motionEntry->source, dispatchEntry->resolvedAction, + inputTarget->inputChannel->getToken()); - break; - } + break; + } } // Remember that we are waiting for this dispatch to complete. @@ -2156,11 +2122,10 @@ void InputDispatcher::enqueueDispatchEntryLocked( // Enqueue the dispatch entry. connection->outboundQueue.enqueueAtTail(dispatchEntry); traceOutboundQueueLength(connection); - } void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, - const sp<IBinder>& newToken) { + const sp<IBinder>& newToken) { int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; uint32_t maskedSource = source & AINPUT_SOURCE_CLASS_MASK; if (maskedSource != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) { @@ -2181,25 +2146,24 @@ void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t a return; } - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible); commandEntry->newToken = newToken; } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection) { + const sp<Connection>& connection) { if (ATRACE_ENABLED()) { std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)", - connection->getInputChannelName().c_str()); + connection->getInputChannelName().c_str()); ATRACE_NAME(message.c_str()); } #if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ startDispatchCycle", - connection->getInputChannelName().c_str()); + ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str()); #endif - while (connection->status == Connection::STATUS_NORMAL - && !connection->outboundQueue.isEmpty()) { + while (connection->status == Connection::STATUS_NORMAL && + !connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; @@ -2207,70 +2171,77 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - - // Publish the key event. - status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, - keyEntry->deviceId, keyEntry->source, keyEntry->displayId, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - keyEntry->keyCode, keyEntry->scanCode, - keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, - keyEntry->eventTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); + case EventEntry::TYPE_KEY: { + KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); + + // Publish the key event. + status = connection->inputPublisher + .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, + keyEntry->source, keyEntry->displayId, + dispatchEntry->resolvedAction, + dispatchEntry->resolvedFlags, keyEntry->keyCode, + keyEntry->scanCode, keyEntry->metaState, + keyEntry->repeatCount, keyEntry->downTime, + keyEntry->eventTime); + break; + } - PointerCoords scaledCoords[MAX_POINTERS]; - const PointerCoords* usingCoords = motionEntry->pointerCoords; - - // Set the X and Y offset depending on the input source. - float xOffset, yOffset; - if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { - float globalScaleFactor = dispatchEntry->globalScaleFactor; - float wxs = dispatchEntry->windowXScale; - float wys = dispatchEntry->windowYScale; - xOffset = dispatchEntry->xOffset * wxs; - yOffset = dispatchEntry->yOffset * wys; - if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) { - for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i] = motionEntry->pointerCoords[i]; - scaledCoords[i].scale(globalScaleFactor, wxs, wys); + case EventEntry::TYPE_MOTION: { + MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); + + PointerCoords scaledCoords[MAX_POINTERS]; + const PointerCoords* usingCoords = motionEntry->pointerCoords; + + // Set the X and Y offset depending on the input source. + float xOffset, yOffset; + if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && + !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { + float globalScaleFactor = dispatchEntry->globalScaleFactor; + float wxs = dispatchEntry->windowXScale; + float wys = dispatchEntry->windowYScale; + xOffset = dispatchEntry->xOffset * wxs; + yOffset = dispatchEntry->yOffset * wys; + if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) { + for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { + scaledCoords[i] = motionEntry->pointerCoords[i]; + scaledCoords[i].scale(globalScaleFactor, wxs, wys); + } + usingCoords = scaledCoords; } - usingCoords = scaledCoords; - } - } else { - xOffset = 0.0f; - yOffset = 0.0f; + } else { + xOffset = 0.0f; + yOffset = 0.0f; - // We don't want the dispatch target to know. - if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { - for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i].clear(); + // We don't want the dispatch target to know. + if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { + for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { + scaledCoords[i].clear(); + } + usingCoords = scaledCoords; } - usingCoords = scaledCoords; } - } - // Publish the motion event. - status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, - motionEntry->deviceId, motionEntry->source, motionEntry->displayId, - dispatchEntry->resolvedAction, motionEntry->actionButton, - dispatchEntry->resolvedFlags, motionEntry->edgeFlags, - motionEntry->metaState, motionEntry->buttonState, motionEntry->classification, - xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, - motionEntry->downTime, motionEntry->eventTime, - motionEntry->pointerCount, motionEntry->pointerProperties, - usingCoords); - break; - } + // Publish the motion event. + status = connection->inputPublisher + .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, + motionEntry->source, motionEntry->displayId, + dispatchEntry->resolvedAction, + motionEntry->actionButton, + dispatchEntry->resolvedFlags, + motionEntry->edgeFlags, motionEntry->metaState, + motionEntry->buttonState, + motionEntry->classification, xOffset, yOffset, + motionEntry->xPrecision, + motionEntry->yPrecision, motionEntry->downTime, + motionEntry->eventTime, + motionEntry->pointerCount, + motionEntry->pointerProperties, usingCoords); + break; + } - default: - ALOG_ASSERT(false); - return; + default: + ALOG_ASSERT(false); + return; } // Check the result. @@ -2278,24 +2249,25 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, if (status == WOULD_BLOCK) { if (connection->waitQueue.isEmpty()) { ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " - "This is unexpected because the wait queue is empty, so the pipe " - "should be empty and we shouldn't have any problems writing an " - "event to it, status=%d", connection->getInputChannelName().c_str(), - status); + "This is unexpected because the wait queue is empty, so the pipe " + "should be empty and we shouldn't have any problems writing an " + "event to it, status=%d", + connection->getInputChannelName().c_str(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } else { // Pipe is full and we are waiting for the app to finish process some events // before sending more events to it. #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " - "waiting for the application to catch up", - connection->getInputChannelName().c_str()); + "waiting for the application to catch up", + connection->getInputChannelName().c_str()); #endif connection->inputPublisherBlocked = true; } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " - "status=%d", connection->getInputChannelName().c_str(), status); + "status=%d", + connection->getInputChannelName().c_str(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } return; @@ -2310,16 +2282,17 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, uint32_t seq, bool handled) { + const sp<Connection>& connection, uint32_t seq, + bool handled) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s", - connection->getInputChannelName().c_str(), seq, toString(handled)); + connection->getInputChannelName().c_str(), seq, toString(handled)); #endif connection->inputPublisherBlocked = false; - if (connection->status == Connection::STATUS_BROKEN - || connection->status == Connection::STATUS_ZOMBIE) { + if (connection->status == Connection::STATUS_BROKEN || + connection->status == Connection::STATUS_ZOMBIE) { return; } @@ -2328,10 +2301,11 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, } void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, bool notify) { + const sp<Connection>& connection, + bool notify) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", - connection->getInputChannelName().c_str(), toString(notify)); + connection->getInputChannelName().c_str(), toString(notify)); #endif // Clear the dispatch queues. @@ -2375,7 +2349,8 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); if (connectionIndex < 0) { ALOGE("Received spurious receive callback for unknown input channel. " - "fd=%d, events=0x%x", fd, events); + "fd=%d, events=0x%x", + fd, events); return 0; // remove the callback } @@ -2384,7 +2359,8 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { if (!(events & ALOOPER_EVENT_INPUT)) { ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " - "events=0x%x", connection->getInputChannelName().c_str(), events); + "events=0x%x", + connection->getInputChannelName().c_str(), events); return 1; } @@ -2411,7 +2387,7 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { notify = status != DEAD_OBJECT || !connection->monitor; if (notify) { ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", - connection->getInputChannelName().c_str(), status); + connection->getInputChannelName().c_str(), status); } } else { // Monitor channels are never explicitly unregistered. @@ -2420,25 +2396,25 @@ int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { notify = !connection->monitor; if (notify) { ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. " - "events=0x%x", connection->getInputChannelName().c_str(), events); + "events=0x%x", + connection->getInputChannelName().c_str(), events); } } // Unregister the channel. d->unregisterInputChannelLocked(connection->inputChannel, notify); return 0; // remove the callback - } // release lock + } // release lock } -void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked ( +void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options) { for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(i), options); + synthesizeCancelationEventsForConnectionLocked(mConnectionsByFd.valueAt(i), options); } } -void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked ( +void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( const CancelationOptions& options) { synthesizeCancelationEventsForMonitorsLocked(options, mGlobalMonitorsByDisplay); synthesizeCancelationEventsForMonitorsLocked(options, mGestureMonitorsByDisplay); @@ -2459,8 +2435,7 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( const sp<InputChannel>& channel, const CancelationOptions& options) { ssize_t index = getConnectionIndexLocked(channel); if (index >= 0) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(index), options); + synthesizeCancelationEventsForConnectionLocked(mConnectionsByFd.valueAt(index), options); } } @@ -2473,32 +2448,31 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( nsecs_t currentTime = now(); std::vector<EventEntry*> cancelationEvents; - connection->inputState.synthesizeCancelationEvents(currentTime, - cancelationEvents, options); + connection->inputState.synthesizeCancelationEvents(currentTime, cancelationEvents, options); if (!cancelationEvents.empty()) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync " - "with reality: %s, mode=%d.", - connection->getInputChannelName().c_str(), cancelationEvents.size(), - options.reason, options.mode); + "with reality: %s, mode=%d.", + connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason, + options.mode); #endif for (size_t i = 0; i < cancelationEvents.size(); i++) { EventEntry* cancelationEventEntry = cancelationEvents[i]; switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetails("cancel - ", - static_cast<KeyEntry*>(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetails("cancel - ", - static_cast<MotionEntry*>(cancelationEventEntry)); - break; + case EventEntry::TYPE_KEY: + logOutboundKeyDetails("cancel - ", + static_cast<KeyEntry*>(cancelationEventEntry)); + break; + case EventEntry::TYPE_MOTION: + logOutboundMotionDetails("cancel - ", + static_cast<MotionEntry*>(cancelationEventEntry)); + break; } InputTarget target; - sp<InputWindowHandle> windowHandle = getWindowHandleLocked( - connection->inputChannel->getToken()); + sp<InputWindowHandle> windowHandle = + getWindowHandleLocked(connection->inputChannel->getToken()); if (windowHandle != nullptr) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); target.xOffset = -windowInfo->frameLeft; @@ -2515,7 +2489,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( target.flags = InputTarget::FLAG_DISPATCH_AS_IS; enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref - &target, InputTarget::FLAG_DISPATCH_AS_IS); + &target, InputTarget::FLAG_DISPATCH_AS_IS); cancelationEventEntry->release(); } @@ -2524,8 +2498,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } } -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]; @@ -2536,7 +2510,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet uint32_t splitPointerCount = 0; for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; - originalPointerIndex++) { + originalPointerIndex++) { const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); @@ -2556,16 +2530,16 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers // in this way. ALOGW("Dropping split motion event because the pointer count is %d but " - "we expected there to be %d pointers. This probably means we received " - "a broken sequence of pointer ids from the input device.", - splitPointerCount, pointerIds.count()); + "we expected there to be %d pointers. This probably means we received " + "a broken sequence of pointer ids from the input device.", + splitPointerCount, pointerIds.count()); return nullptr; } int32_t action = originalMotionEntry->action; int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { + if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN || + maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; @@ -2574,15 +2548,16 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet if (pointerIds.count() == 1) { // The first/last pointer went down/up. action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; + ? AMOTION_EVENT_ACTION_DOWN + : AMOTION_EVENT_ACTION_UP; } else { // A secondary pointer went down/up. uint32_t splitPointerIndex = 0; while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) { splitPointerIndex += 1; } - action = maskedAction | (splitPointerIndex - << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + action = maskedAction | + (splitPointerIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } } else { // An unrelated pointer changed. @@ -2590,24 +2565,16 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet } } - MotionEntry* splitMotionEntry = new MotionEntry( - originalMotionEntry->sequenceNum, - originalMotionEntry->eventTime, - originalMotionEntry->deviceId, - originalMotionEntry->source, - originalMotionEntry->displayId, - originalMotionEntry->policyFlags, - action, - originalMotionEntry->actionButton, - originalMotionEntry->flags, - originalMotionEntry->metaState, - originalMotionEntry->buttonState, - originalMotionEntry->classification, - originalMotionEntry->edgeFlags, - originalMotionEntry->xPrecision, - originalMotionEntry->yPrecision, - originalMotionEntry->downTime, - splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0); + MotionEntry* splitMotionEntry = + new MotionEntry(originalMotionEntry->sequenceNum, originalMotionEntry->eventTime, + originalMotionEntry->deviceId, originalMotionEntry->source, + originalMotionEntry->displayId, originalMotionEntry->policyFlags, + action, originalMotionEntry->actionButton, originalMotionEntry->flags, + originalMotionEntry->metaState, originalMotionEntry->buttonState, + originalMotionEntry->classification, originalMotionEntry->edgeFlags, + originalMotionEntry->xPrecision, originalMotionEntry->yPrecision, + originalMotionEntry->downTime, splitPointerCount, + splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry->injectionState) { splitMotionEntry->injectionState = originalMotionEntry->injectionState; @@ -2643,7 +2610,7 @@ void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChange * This will potentially overwrite keyCode and metaState. */ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int32_t action, - int32_t& keyCode, int32_t& metaState) { + int32_t& keyCode, int32_t& metaState) { if (metaState & AMETA_META_ON && action == AKEY_EVENT_ACTION_DOWN) { int32_t newKeyCode = AKEYCODE_UNKNOWN; if (keyCode == AKEYCODE_DEL) { @@ -2675,12 +2642,12 @@ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int3 void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyKey - eventTime=%" PRId64 - ", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, - args->action, args->flags, args->keyCode, args->scanCode, - args->metaState, args->downTime); + ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 + "policyFlags=0x%x, action=0x%x, " + "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64, + args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, + args->action, args->flags, args->keyCode, args->scanCode, args->metaState, + args->downTime); #endif if (!validateKeyEvent(args->action)) { return; @@ -2706,15 +2673,14 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState); KeyEvent event; - event.initialize(args->deviceId, args->source, args->displayId, args->action, - flags, keyCode, args->scanCode, metaState, repeatCount, - args->downTime, args->eventTime); + event.initialize(args->deviceId, args->source, args->displayId, args->action, flags, keyCode, + args->scanCode, metaState, repeatCount, args->downTime, args->eventTime); android::base::Timer t; mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } bool needWake; @@ -2732,10 +2698,10 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { mLock.lock(); } - KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime, - args->deviceId, args->source, args->displayId, policyFlags, - args->action, flags, keyCode, args->scanCode, - metaState, repeatCount, args->downTime); + KeyEntry* newEntry = + new KeyEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, + args->displayId, policyFlags, args->action, flags, keyCode, + args->scanCode, metaState, repeatCount, args->downTime); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2753,32 +2719,31 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, - args->action, args->actionButton, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); + ", policyFlags=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, + args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, + args->action, args->actionButton, args->flags, args->metaState, args->buttonState, + args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, args->pointerProperties[i].id, - args->pointerProperties[i].toolType, - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + "x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " + "orientation=%f", + i, args->pointerProperties[i].id, args->pointerProperties[i].toolType, + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif - if (!validateMotionEvent(args->action, args->actionButton, - args->pointerCount, args->pointerProperties)) { + if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount, + args->pointerProperties)) { return; } @@ -2789,7 +2754,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } bool needWake; @@ -2800,12 +2765,11 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->deviceId, args->source, args->displayId, - args->action, args->actionButton, - args->flags, args->edgeFlags, args->metaState, args->buttonState, - args->classification, 0, 0, args->xPrecision, args->yPrecision, - args->downTime, args->eventTime, - args->pointerCount, args->pointerProperties, args->pointerCoords); + event.initialize(args->deviceId, args->source, args->displayId, args->action, + args->actionButton, args->flags, args->edgeFlags, args->metaState, + args->buttonState, args->classification, 0, 0, args->xPrecision, + args->yPrecision, args->downTime, args->eventTime, args->pointerCount, + args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { @@ -2816,12 +2780,13 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { } // Just enqueue a new motion event. - MotionEntry* newEntry = new MotionEntry(args->sequenceNum, args->eventTime, - args->deviceId, args->source, args->displayId, policyFlags, - args->action, args->actionButton, args->flags, - args->metaState, args->buttonState, args->classification, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, - args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0); + MotionEntry* newEntry = + new MotionEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, + args->displayId, policyFlags, args->action, args->actionButton, + args->flags, args->metaState, args->buttonState, + args->classification, args->edgeFlags, args->xPrecision, + args->yPrecision, args->downTime, args->pointerCount, + args->pointerProperties, args->pointerCoords, 0, 0); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2839,20 +2804,19 @@ bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, " - "switchMask=0x%08x", - args->eventTime, args->policyFlags, args->switchValues, args->switchMask); + "switchMask=0x%08x", + args->eventTime, args->policyFlags, args->switchValues, args->switchMask); #endif uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->notifySwitch(args->eventTime, - args->switchValues, args->switchMask, policyFlags); + mPolicy->notifySwitch(args->eventTime, args->switchValues, args->switchMask, policyFlags); } void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", - args->eventTime, args->deviceId); + ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime, + args->deviceId); #endif bool needWake; @@ -2869,13 +2833,13 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { } } -int32_t InputDispatcher::injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) { +int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid, + int32_t injectorUid, int32_t syncMode, + int32_t timeoutMillis, uint32_t policyFlags) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); + "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", + event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); #endif nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); @@ -2888,104 +2852,107 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, EventEntry* firstInjectedEntry; EventEntry* lastInjectedEntry; switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - KeyEvent keyEvent; - keyEvent.initialize(*static_cast<const KeyEvent*>(event)); - int32_t action = keyEvent.getAction(); - if (! validateKeyEvent(action)) { - return INPUT_EVENT_INJECTION_FAILED; - } + case AINPUT_EVENT_TYPE_KEY: { + KeyEvent keyEvent; + keyEvent.initialize(*static_cast<const KeyEvent*>(event)); + int32_t action = keyEvent.getAction(); + if (!validateKeyEvent(action)) { + return INPUT_EVENT_INJECTION_FAILED; + } + + int32_t flags = keyEvent.getFlags(); + int32_t keyCode = keyEvent.getKeyCode(); + int32_t metaState = keyEvent.getMetaState(); + accelerateMetaShortcuts(keyEvent.getDeviceId(), action, + /*byref*/ keyCode, /*byref*/ metaState); + keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), + keyEvent.getDisplayId(), action, flags, keyCode, + keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), + keyEvent.getDownTime(), keyEvent.getEventTime()); + + if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { + policyFlags |= POLICY_FLAG_VIRTUAL; + } - int32_t flags = keyEvent.getFlags(); - int32_t keyCode = keyEvent.getKeyCode(); - int32_t metaState = keyEvent.getMetaState(); - accelerateMetaShortcuts(keyEvent.getDeviceId(), action, - /*byref*/ keyCode, /*byref*/ metaState); - keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(), - action, flags, keyCode, keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(), - keyEvent.getDownTime(), keyEvent.getEventTime()); + if (!(policyFlags & POLICY_FLAG_FILTERED)) { + android::base::Timer t; + mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags); + if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { + ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", + std::to_string(t.duration().count()).c_str()); + } + } - if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { - policyFlags |= POLICY_FLAG_VIRTUAL; + mLock.lock(); + firstInjectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, + keyEvent.getEventTime(), keyEvent.getDeviceId(), + keyEvent.getSource(), keyEvent.getDisplayId(), + policyFlags, action, flags, keyEvent.getKeyCode(), + keyEvent.getScanCode(), keyEvent.getMetaState(), + keyEvent.getRepeatCount(), keyEvent.getDownTime()); + lastInjectedEntry = firstInjectedEntry; + break; } - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - android::base::Timer t; - mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags); - if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { - ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + case AINPUT_EVENT_TYPE_MOTION: { + const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); + int32_t action = motionEvent->getAction(); + size_t pointerCount = motionEvent->getPointerCount(); + const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); + int32_t actionButton = motionEvent->getActionButton(); + int32_t displayId = motionEvent->getDisplayId(); + if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { + return INPUT_EVENT_INJECTION_FAILED; } - } - mLock.lock(); - firstInjectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(), - keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(), - policyFlags, action, flags, - keyEvent.getKeyCode(), keyEvent.getScanCode(), keyEvent.getMetaState(), - keyEvent.getRepeatCount(), keyEvent.getDownTime()); - lastInjectedEntry = firstInjectedEntry; - break; - } - - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); - int32_t action = motionEvent->getAction(); - size_t pointerCount = motionEvent->getPointerCount(); - const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); - int32_t actionButton = motionEvent->getActionButton(); - int32_t displayId = motionEvent->getDisplayId(); - if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { - return INPUT_EVENT_INJECTION_FAILED; - } + if (!(policyFlags & POLICY_FLAG_FILTERED)) { + nsecs_t eventTime = motionEvent->getEventTime(); + android::base::Timer t; + mPolicy->interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags); + if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { + ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", + std::to_string(t.duration().count()).c_str()); + } + } - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - nsecs_t eventTime = motionEvent->getEventTime(); - android::base::Timer t; - mPolicy->interceptMotionBeforeQueueing(displayId, eventTime, /*byref*/ policyFlags); - if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { - ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", - std::to_string(t.duration().count()).c_str()); + mLock.lock(); + const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); + const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); + firstInjectedEntry = + new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), + motionEvent->getDisplayId(), policyFlags, action, actionButton, + motionEvent->getFlags(), motionEvent->getMetaState(), + motionEvent->getButtonState(), motionEvent->getClassification(), + motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), + motionEvent->getYPrecision(), motionEvent->getDownTime(), + uint32_t(pointerCount), pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); + lastInjectedEntry = firstInjectedEntry; + for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { + sampleEventTimes += 1; + samplePointerCoords += pointerCount; + MotionEntry* nextInjectedEntry = + new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), + motionEvent->getDisplayId(), policyFlags, action, + actionButton, motionEvent->getFlags(), + motionEvent->getMetaState(), motionEvent->getButtonState(), + motionEvent->getClassification(), + motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), + motionEvent->getYPrecision(), motionEvent->getDownTime(), + uint32_t(pointerCount), pointerProperties, + samplePointerCoords, motionEvent->getXOffset(), + motionEvent->getYOffset()); + lastInjectedEntry->next = nextInjectedEntry; + lastInjectedEntry = nextInjectedEntry; } + break; } - mLock.lock(); - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - firstInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), motionEvent->getDisplayId(), - policyFlags, - action, actionButton, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getClassification(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, samplePointerCoords, - motionEvent->getXOffset(), motionEvent->getYOffset()); - lastInjectedEntry = firstInjectedEntry; - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - MotionEntry* nextInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, - *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), - motionEvent->getDisplayId(), policyFlags, - action, actionButton, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getClassification(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, samplePointerCoords, - motionEvent->getXOffset(), motionEvent->getYOffset()); - lastInjectedEntry->next = nextInjectedEntry; - lastInjectedEntry = nextInjectedEntry; - } - break; - } - - default: - ALOGW("Cannot inject event of type %d", event->getType()); - return INPUT_EVENT_INJECTION_FAILED; + default: + ALOGW("Cannot inject event of type %d", event->getType()); + return INPUT_EVENT_INJECTION_FAILED; } InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); @@ -2997,7 +2964,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, lastInjectedEntry->injectionState = injectionState; bool needWake = false; - for (EventEntry* entry = firstInjectedEntry; entry != nullptr; ) { + for (EventEntry* entry = firstInjectedEntry; entry != nullptr;) { EventEntry* nextEntry = entry->next; needWake |= enqueueInboundEventLocked(entry); entry = nextEntry; @@ -3026,7 +2993,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, if (remainingTimeout <= 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Timed out waiting for injection result " - "to become available."); + "to become available."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; @@ -3035,18 +3002,18 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, mInjectionResultAvailable.wait_for(_l, std::chrono::nanoseconds(remainingTimeout)); } - if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED - && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { + if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED && + syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { while (injectionState->pendingForegroundDispatches != 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", - injectionState->pendingForegroundDispatches); + injectionState->pendingForegroundDispatches); #endif nsecs_t remainingTimeout = endTime - now(); if (remainingTimeout <= 0) { #if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for pending foreground " - "dispatches to finish."); + ALOGD("injectInputEvent - Timed out waiting for pending foreground " + "dispatches to finish."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; @@ -3062,16 +3029,16 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, #if DEBUG_INJECTION ALOGD("injectInputEvent - Finished with result %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectorPid, injectorUid); + "injectorPid=%d, injectorUid=%d", + injectionResult, injectorPid, injectorUid); #endif return injectionResult; } bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { - return injectorUid == 0 - || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); + return injectorUid == 0 || + mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); } void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionResult) { @@ -3079,26 +3046,25 @@ void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionRes if (injectionState) { #if DEBUG_INJECTION ALOGD("Setting input event injection result to %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectionState->injectorPid, injectionState->injectorUid); + "injectorPid=%d, injectorUid=%d", + injectionResult, injectionState->injectorPid, injectionState->injectorUid); #endif - if (injectionState->injectionIsAsync - && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { + if (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { // Log the outcome since the injector did not wait for the injection result. switch (injectionResult) { - case INPUT_EVENT_INJECTION_SUCCEEDED: - ALOGV("Asynchronous input event injection succeeded."); - break; - case INPUT_EVENT_INJECTION_FAILED: - ALOGW("Asynchronous input event injection failed."); - break; - case INPUT_EVENT_INJECTION_PERMISSION_DENIED: - ALOGW("Asynchronous input event injection permission denied."); - break; - case INPUT_EVENT_INJECTION_TIMED_OUT: - ALOGW("Asynchronous input event injection timed out."); - break; + case INPUT_EVENT_INJECTION_SUCCEEDED: + ALOGV("Asynchronous input event injection succeeded."); + break; + case INPUT_EVENT_INJECTION_FAILED: + ALOGW("Asynchronous input event injection failed."); + break; + case INPUT_EVENT_INJECTION_PERMISSION_DENIED: + ALOGW("Asynchronous input event injection permission denied."); + break; + case INPUT_EVENT_INJECTION_TIMED_OUT: + ALOGW("Asynchronous input event injection timed out."); + break; } } @@ -3129,7 +3095,7 @@ std::vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked( int32_t displayId) const { std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>::const_iterator it = mWindowHandlesByDisplay.find(displayId); - if(it != mWindowHandlesByDisplay.end()) { + if (it != mWindowHandlesByDisplay.end()) { return it->second; } @@ -3157,9 +3123,9 @@ bool InputDispatcher::hasWindowHandleLocked(const sp<InputWindowHandle>& windowH if (handle->getToken() == windowHandle->getToken()) { if (windowHandle->getInfo()->displayId != it.first) { ALOGE("Found window %s in display %" PRId32 - ", but it should belong to display %" PRId32, - windowHandle->getName().c_str(), it.first, - windowHandle->getInfo()->displayId); + ", but it should belong to display %" PRId32, + windowHandle->getName().c_str(), it.first, + windowHandle->getInfo()->displayId); } return true; } @@ -3184,7 +3150,8 @@ sp<InputChannel> InputDispatcher::getInputChannelLocked(const sp<IBinder>& token * For removed handle, check if need to send a cancel event if already in touch. */ void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& inputWindowHandles, - int32_t displayId, const sp<ISetInputWindowsListener>& setInputWindowsListener) { + int32_t displayId, + const sp<ISetInputWindowsListener>& setInputWindowsListener) { #if DEBUG_FOCUS ALOGD("setInputWindows displayId=%" PRId32, displayId); #endif @@ -3251,8 +3218,8 @@ void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& for (const sp<InputWindowHandle>& windowHandle : newHandles) { // Set newFocusedWindowHandle to the top most focused window instead of the last one - if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus - && windowHandle->getInfo()->visible) { + if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus && + windowHandle->getInfo()->visible) { newFocusedWindowHandle = windowHandle; } if (windowHandle == mLastHoverWindowHandle) { @@ -3275,22 +3242,21 @@ void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& if (oldFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus left window: %s in display %" PRId32, - oldFocusedWindowHandle->getName().c_str(), displayId); + oldFocusedWindowHandle->getName().c_str(), displayId); #endif - sp<InputChannel> focusedInputChannel = getInputChannelLocked( - oldFocusedWindowHandle->getToken()); + sp<InputChannel> focusedInputChannel = + getInputChannelLocked(oldFocusedWindowHandle->getToken()); if (focusedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "focus left window"); - synthesizeCancelationEventsForInputChannelLocked( - focusedInputChannel, options); + "focus left window"); + synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options); } mFocusedWindowHandlesByDisplay.erase(displayId); } if (newFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus entered window: %s in display %" PRId32, - newFocusedWindowHandle->getName().c_str(), displayId); + newFocusedWindowHandle->getName().c_str(), displayId); #endif mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; } @@ -3298,30 +3264,29 @@ void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& if (mFocusedDisplayId == displayId) { onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle); } - } ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); if (stateIndex >= 0) { TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); - for (size_t i = 0; i < state.windows.size(); ) { + for (size_t i = 0; i < state.windows.size();) { TouchedWindow& touchedWindow = state.windows[i]; if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS ALOGD("Touched window was removed: %s in display %" PRId32, - touchedWindow.windowHandle->getName().c_str(), displayId); + touchedWindow.windowHandle->getName().c_str(), displayId); #endif sp<InputChannel> touchedInputChannel = getInputChannelLocked(touchedWindow.windowHandle->getToken()); if (touchedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked( - touchedInputChannel, options); + "touched window was removed"); + synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, + options); } state.windows.erase(state.windows.begin() + i); } else { - ++i; + ++i; } } } @@ -3372,7 +3337,7 @@ void InputDispatcher::setFocusedApplication( } #if DEBUG_FOCUS - //logDispatchStateLocked(); + // logDispatchStateLocked(); #endif } // release lock @@ -3401,11 +3366,11 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId); if (oldFocusedWindowHandle != nullptr) { sp<InputChannel> inputChannel = - getInputChannelLocked(oldFocusedWindowHandle->getToken()); + getInputChannelLocked(oldFocusedWindowHandle->getToken()); if (inputChannel != nullptr) { - CancelationOptions options( - CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "The display which contains this window no longer has focus."); + CancelationOptions + options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, + "The display which contains this window no longer has focus."); options.displayId = ADISPLAY_ID_NONE; synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); } @@ -3424,8 +3389,8 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputWindowHandle>& windowHandle = it.second; - ALOGE("Display #%" PRId32 " has focused window: '%s'\n", - displayId, windowHandle->getName().c_str()); + ALOGE("Display #%" PRId32 " has focused window: '%s'\n", displayId, + windowHandle->getName().c_str()); } } } @@ -3515,7 +3480,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< } #if DEBUG_FOCUS ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s", - fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str()); + fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str()); #endif if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) { #if DEBUG_FOCUS @@ -3535,9 +3500,9 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< state.windows.erase(state.windows.begin() + i); - int32_t newTargetFlags = oldTargetFlags - & (InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); + int32_t newTargetFlags = oldTargetFlags & + (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT | + InputTarget::FLAG_DISPATCH_AS_IS); state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); found = true; @@ -3545,16 +3510,15 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< } } } -Found: + Found: - if (! found) { + if (!found) { #if DEBUG_FOCUS ALOGD("Focus transfer failed because from window did not have focus."); #endif return false; } - sp<InputChannel> fromChannel = getInputChannelLocked(fromToken); sp<InputChannel> toChannel = getInputChannelLocked(toToken); ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); @@ -3564,8 +3528,9 @@ Found: sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex); fromConnection->inputState.copyPointerStateTo(toConnection->inputState); - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "transferring touch focus from this window to another window"); + CancelationOptions + options(CancelationOptions::CANCEL_POINTER_EVENTS, + "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); } @@ -3620,12 +3585,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (auto& it : mFocusedApplicationHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputApplicationHandle>& applicationHandle = it.second; - dump += StringPrintf( - INDENT2 "displayId=%" PRId32 ", name='%s', dispatchingTimeout=%0.3fms\n", - displayId, - applicationHandle->getName().c_str(), - applicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); + dump += StringPrintf(INDENT2 "displayId=%" PRId32 + ", name='%s', dispatchingTimeout=%0.3fms\n", + displayId, applicationHandle->getName().c_str(), + applicationHandle->getDispatchingTimeout( + DEFAULT_INPUT_DISPATCHING_TIMEOUT) / + 1000000.0); } } else { dump += StringPrintf(INDENT "FocusedApplications: <none>\n"); @@ -3636,8 +3601,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputWindowHandle>& windowHandle = it.second; - dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", - displayId, windowHandle->getName().c_str()); + dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, + windowHandle->getName().c_str()); } } else { dump += StringPrintf(INDENT "FocusedWindows: <none>\n"); @@ -3648,16 +3613,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) { const TouchState& state = mTouchStatesByDisplay.valueAt(i); dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", - state.displayId, toString(state.down), toString(state.split), - state.deviceId, state.source); + state.displayId, toString(state.down), toString(state.split), + state.deviceId, state.source); if (!state.windows.empty()) { dump += INDENT3 "Windows:\n"; for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; - dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.windowHandle->getName().c_str(), - touchedWindow.pointerIds.value, - touchedWindow.targetFlags); + dump += StringPrintf(INDENT4 + "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + i, touchedWindow.windowHandle->getName().c_str(), + touchedWindow.pointerIds.value, touchedWindow.targetFlags); } } else { dump += INDENT3 "Windows: <none>\n"; @@ -3666,8 +3631,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT3 "Portal windows:\n"; for (size_t i = 0; i < state.portalWindows.size(); i++) { const sp<InputWindowHandle> portalWindowHandle = state.portalWindows[i]; - dump += StringPrintf(INDENT4 "%zu: name='%s'\n", - i, portalWindowHandle->getName().c_str()); + dump += StringPrintf(INDENT4 "%zu: name='%s'\n", i, + portalWindowHandle->getName().c_str()); } } } @@ -3676,7 +3641,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mWindowHandlesByDisplay.empty()) { - for (auto& it : mWindowHandlesByDisplay) { + for (auto& it : mWindowHandlesByDisplay) { const std::vector<sp<InputWindowHandle>> windowHandles = it.second; dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); if (!windowHandles.empty()) { @@ -3686,28 +3651,31 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, " - "portalToDisplayId=%d, paused=%s, hasFocus=%s, hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=(%f,%f), " - "touchableRegion=", - i, windowInfo->name.c_str(), windowInfo->displayId, - windowInfo->portalToDisplayId, - toString(windowInfo->paused), - toString(windowInfo->hasFocus), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), - toString(windowInfo->canReceiveKeys), - windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, - windowInfo->layer, - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->globalScaleFactor, - windowInfo->windowXScale, windowInfo->windowYScale); + "portalToDisplayId=%d, paused=%s, hasFocus=%s, " + "hasWallpaper=%s, " + "visible=%s, canReceiveKeys=%s, flags=0x%08x, " + "type=0x%08x, layer=%d, " + "frame=[%d,%d][%d,%d], globalScale=%f, " + "windowScale=(%f,%f), " + "touchableRegion=", + i, windowInfo->name.c_str(), windowInfo->displayId, + windowInfo->portalToDisplayId, + toString(windowInfo->paused), + toString(windowInfo->hasFocus), + toString(windowInfo->hasWallpaper), + toString(windowInfo->visible), + toString(windowInfo->canReceiveKeys), + windowInfo->layoutParamsFlags, + windowInfo->layoutParamsType, windowInfo->layer, + windowInfo->frameLeft, windowInfo->frameTop, + windowInfo->frameRight, windowInfo->frameBottom, + windowInfo->globalScaleFactor, windowInfo->windowXScale, + windowInfo->windowYScale); dumpRegion(dump, windowInfo->touchableRegion); dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - windowInfo->ownerPid, windowInfo->ownerUid, - windowInfo->dispatchingTimeout / 1000000.0); + windowInfo->ownerPid, windowInfo->ownerUid, + windowInfo->dispatchingTimeout / 1000000.0); } } else { dump += INDENT2 "Windows: <none>\n"; @@ -3718,16 +3686,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mGlobalMonitorsByDisplay.empty() || !mGestureMonitorsByDisplay.empty()) { - for (auto& it : mGlobalMonitorsByDisplay) { + for (auto& it : mGlobalMonitorsByDisplay) { const std::vector<Monitor>& monitors = it.second; dump += StringPrintf(INDENT "Global monitors in display %" PRId32 ":\n", it.first); dumpMonitors(dump, monitors); - } - for (auto& it : mGestureMonitorsByDisplay) { + } + for (auto& it : mGestureMonitorsByDisplay) { const std::vector<Monitor>& monitors = it.second; dump += StringPrintf(INDENT "Gesture monitors in display %" PRId32 ":\n", it.first); dumpMonitors(dump, monitors); - } + } } else { dump += INDENT "Monitors: <none>\n"; } @@ -3740,8 +3708,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) { dump += INDENT2; entry->appendDescription(dump); - dump += StringPrintf(", age=%0.1fms\n", - (currentTime - entry->eventTime) * 0.000001f); + dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { dump += INDENT "RecentQueue: <empty>\n"; @@ -3753,7 +3720,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT2; mPendingEvent->appendDescription(dump); dump += StringPrintf(", age=%0.1fms\n", - (currentTime - mPendingEvent->eventTime) * 0.000001f); + (currentTime - mPendingEvent->eventTime) * 0.000001f); } else { dump += INDENT "PendingEvent: <none>\n"; } @@ -3764,8 +3731,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) { dump += INDENT2; entry->appendDescription(dump); - dump += StringPrintf(", age=%0.1fms\n", - (currentTime - entry->eventTime) * 0.000001f); + dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { dump += INDENT "InboundQueue: <empty>\n"; @@ -3776,8 +3742,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (size_t i = 0; i < mReplacedKeys.size(); i++) { const KeyReplacement& replacement = mReplacedKeys.keyAt(i); int32_t newKeyCode = mReplacedKeys.valueAt(i); - dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", - i, replacement.keyCode, replacement.deviceId, newKeyCode); + dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", i, + replacement.keyCode, replacement.deviceId, newKeyCode); } } else { dump += INDENT "ReplacedKeys: <empty>\n"; @@ -3788,22 +3754,22 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (size_t i = 0; i < mConnectionsByFd.size(); i++) { const sp<Connection>& connection = mConnectionsByFd.valueAt(i); dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', " - "status=%s, monitor=%s, inputPublisherBlocked=%s\n", - i, connection->getInputChannelName().c_str(), - connection->getWindowName().c_str(), - connection->getStatusLabel(), toString(connection->monitor), - toString(connection->inputPublisherBlocked)); + "status=%s, monitor=%s, inputPublisherBlocked=%s\n", + i, connection->getInputChannelName().c_str(), + connection->getWindowName().c_str(), connection->getStatusLabel(), + toString(connection->monitor), + toString(connection->inputPublisherBlocked)); if (!connection->outboundQueue.isEmpty()) { dump += StringPrintf(INDENT3 "OutboundQueue: length=%u\n", - connection->outboundQueue.count()); + connection->outboundQueue.count()); for (DispatchEntry* entry = connection->outboundQueue.head; entry; - entry = entry->next) { + entry = entry->next) { dump.append(INDENT4); entry->eventEntry->appendDescription(dump); dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f); + entry->targetFlags, entry->resolvedAction, + (currentTime - entry->eventEntry->eventTime) * 0.000001f); } } else { dump += INDENT3 "OutboundQueue: <empty>\n"; @@ -3811,16 +3777,16 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (!connection->waitQueue.isEmpty()) { dump += StringPrintf(INDENT3 "WaitQueue: length=%u\n", - connection->waitQueue.count()); + connection->waitQueue.count()); for (DispatchEntry* entry = connection->waitQueue.head; entry; - entry = entry->next) { + entry = entry->next) { dump += INDENT4; entry->eventEntry->appendDescription(dump); dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, " - "age=%0.1fms, wait=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f, - (currentTime - entry->deliveryTime) * 0.000001f); + "age=%0.1fms, wait=%0.1fms\n", + entry->targetFlags, entry->resolvedAction, + (currentTime - entry->eventEntry->eventTime) * 0.000001f, + (currentTime - entry->deliveryTime) * 0.000001f); } } else { dump += INDENT3 "WaitQueue: <empty>\n"; @@ -3832,16 +3798,15 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (isAppSwitchPendingLocked()) { dump += StringPrintf(INDENT "AppSwitch: pending, due in %0.1fms\n", - (mAppSwitchDueTime - now()) / 1000000.0); + (mAppSwitchDueTime - now()) / 1000000.0); } else { dump += INDENT "AppSwitch: not pending\n"; } dump += INDENT "Configuration:\n"; - dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n", - mConfig.keyRepeatDelay * 0.000001f); + dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f); dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %0.1fms\n", - mConfig.keyRepeatTimeout * 0.000001f); + mConfig.keyRepeatTimeout * 0.000001f); } void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) { @@ -3855,10 +3820,10 @@ void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor> } status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, - int32_t displayId) { + int32_t displayId) { #if DEBUG_REGISTRATION ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32, - inputChannel->getName().c_str(), displayId); + inputChannel->getName().c_str(), displayId); #endif { // acquire lock @@ -3866,7 +3831,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan if (getConnectionIndexLocked(inputChannel) >= 0) { ALOGW("Attempted to register already registered input channel '%s'", - inputChannel->getName().c_str()); + inputChannel->getName().c_str()); return BAD_VALUE; } @@ -3885,7 +3850,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan } status_t InputDispatcher::registerInputMonitor(const sp<InputChannel>& inputChannel, - int32_t displayId, bool isGestureMonitor) { + int32_t displayId, bool isGestureMonitor) { { // acquire lock std::scoped_lock _l(mLock); @@ -3905,13 +3870,11 @@ status_t InputDispatcher::registerInputMonitor(const sp<InputChannel>& inputChan mConnectionsByFd.add(fd, connection); mInputChannelsByToken[inputChannel->getToken()] = inputChannel; - auto& monitorsByDisplay = isGestureMonitor - ? mGestureMonitorsByDisplay - : mGlobalMonitorsByDisplay; + auto& monitorsByDisplay = + isGestureMonitor ? mGestureMonitorsByDisplay : mGlobalMonitorsByDisplay; monitorsByDisplay[displayId].emplace_back(inputChannel); mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); - } // Wake the looper because some connections have changed. mLooper->wake(); @@ -3939,11 +3902,11 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh } status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, - bool notify) { + bool notify) { ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex < 0) { ALOGW("Attempted to unregister already unregistered input channel '%s'", - inputChannel->getName().c_str()); + inputChannel->getName().c_str()); return BAD_VALUE; } @@ -3970,16 +3933,17 @@ void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputCh removeMonitorChannelLocked(inputChannel, mGestureMonitorsByDisplay); } -void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel, +void InputDispatcher::removeMonitorChannelLocked( + const sp<InputChannel>& inputChannel, std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) { - for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end(); ) { + for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end();) { std::vector<Monitor>& monitors = it->second; const size_t numMonitors = monitors.size(); for (size_t i = 0; i < numMonitors; i++) { - if (monitors[i].inputChannel == inputChannel) { - monitors.erase(monitors.begin() + i); - break; - } + if (monitors[i].inputChannel == inputChannel) { + monitors.erase(monitors.begin() + i); + break; + } } if (monitors.empty()) { it = monitorsByDisplay.erase(it); @@ -4015,14 +3979,14 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { } if (!foundDeviceId || !state.down) { ALOGW("Attempted to pilfer points from a monitor without any on-going pointer streams." - " Ignoring."); + " Ignoring."); return BAD_VALUE; } int32_t deviceId = foundDeviceId.value(); // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "gesture monitor stole pointer stream"); + "gesture monitor stole pointer stream"); options.deviceId = deviceId; options.displayId = displayId; for (const TouchedWindow& window : state.windows) { @@ -4035,7 +3999,6 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { return OK; } - std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked( const sp<IBinder>& token) { for (const auto& it : mGestureMonitorsByDisplay) { @@ -4064,46 +4027,47 @@ ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputC return -1; } -void InputDispatcher::onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); +void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime, + const sp<Connection>& connection, uint32_t seq, + bool handled) { + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doDispatchCycleFinishedLockedInterruptible); commandEntry->connection = connection; commandEntry->eventTime = currentTime; commandEntry->seq = seq; commandEntry->handled = handled; } -void InputDispatcher::onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp<Connection>& connection) { +void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime, + const sp<Connection>& connection) { ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", - connection->getInputChannelName().c_str()); + connection->getInputChannelName().c_str()); - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); commandEntry->connection = connection; } void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus, - const sp<InputWindowHandle>& newFocus) { + const sp<InputWindowHandle>& newFocus) { sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr; sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr; - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyFocusChangedLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doNotifyFocusChangedLockedInterruptible); commandEntry->oldToken = oldToken; commandEntry->newToken = newToken; } -void InputDispatcher::onANRLocked( - nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) { +void InputDispatcher::onANRLocked(nsecs_t currentTime, + const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime, + nsecs_t waitStartTime, const char* reason) { float dispatchLatency = (currentTime - eventTime) * 0.000001f; float waitDuration = (currentTime - waitStartTime) * 0.000001f; ALOGI("Application is not responding: %s. " - "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), - dispatchLatency, waitDuration, reason); + "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", + getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), dispatchLatency, + waitDuration, reason); // Capture a record of the InputDispatcher state at the time of the ANR. time_t t = time(nullptr); @@ -4114,23 +4078,23 @@ void InputDispatcher::onANRLocked( mLastANRState.clear(); mLastANRState += INDENT "ANR:\n"; mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr); - mLastANRState += StringPrintf(INDENT2 "Window: %s\n", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str()); + mLastANRState += + StringPrintf(INDENT2 "Window: %s\n", + getApplicationWindowLabel(applicationHandle, windowHandle).c_str()); mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason); dumpDispatchStateLocked(mLastANRState); - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyANRLockedInterruptible); + CommandEntry* commandEntry = + postCommandLocked(&InputDispatcher::doNotifyANRLockedInterruptible); commandEntry->inputApplicationHandle = applicationHandle; - commandEntry->inputChannel = windowHandle != nullptr ? - getInputChannelLocked(windowHandle->getToken()) : nullptr; + commandEntry->inputChannel = + windowHandle != nullptr ? getInputChannelLocked(windowHandle->getToken()) : nullptr; commandEntry->reason = reason; } -void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible ( - CommandEntry* commandEntry) { +void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); mPolicy->notifyConfigurationChanged(commandEntry->eventTime); @@ -4138,8 +4102,7 @@ void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible ( mLock.lock(); } -void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( - CommandEntry* commandEntry) { +void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) { sp<Connection> connection = commandEntry->connection; if (connection->status != Connection::STATUS_ZOMBIE) { @@ -4151,8 +4114,7 @@ void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( } } -void InputDispatcher::doNotifyFocusChangedLockedInterruptible( - CommandEntry* commandEntry) { +void InputDispatcher::doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) { sp<IBinder> oldToken = commandEntry->oldToken; sp<IBinder> newToken = commandEntry->newToken; mLock.unlock(); @@ -4160,19 +4122,18 @@ void InputDispatcher::doNotifyFocusChangedLockedInterruptible( mLock.lock(); } -void InputDispatcher::doNotifyANRLockedInterruptible( - CommandEntry* commandEntry) { +void InputDispatcher::doNotifyANRLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); - nsecs_t newTimeout = mPolicy->notifyANR( - commandEntry->inputApplicationHandle, - commandEntry->inputChannel ? commandEntry->inputChannel->getToken() : nullptr, - commandEntry->reason); + nsecs_t newTimeout = + mPolicy->notifyANR(commandEntry->inputApplicationHandle, + commandEntry->inputChannel ? commandEntry->inputChannel->getToken() + : nullptr, + commandEntry->reason); mLock.lock(); - resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, - commandEntry->inputChannel); + resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel); } void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( @@ -4185,13 +4146,13 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( mLock.unlock(); android::base::Timer t; - sp<IBinder> token = commandEntry->inputChannel != nullptr ? - commandEntry->inputChannel->getToken() : nullptr; - nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, - &event, entry->policyFlags); + sp<IBinder> token = commandEntry->inputChannel != nullptr + ? commandEntry->inputChannel->getToken() + : nullptr; + nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry->policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms", - std::to_string(t.duration().count()).c_str()); + std::to_string(t.duration().count()).c_str()); } mLock.lock(); @@ -4213,8 +4174,7 @@ void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntr mLock.lock(); } -void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( - CommandEntry* commandEntry) { +void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) { sp<Connection> connection = commandEntry->connection; nsecs_t finishTime = commandEntry->eventTime; uint32_t seq = commandEntry->seq; @@ -4227,7 +4187,7 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { std::string msg = StringPrintf("Window '%s' spent %0.1fms processing the last input event: ", - connection->getWindowName().c_str(), eventDuration * 0.000001f); + connection->getWindowName().c_str(), eventDuration * 0.000001f); dispatchEntry->eventEntry->appendDescription(msg); ALOGI("%s", msg.c_str()); } @@ -4235,12 +4195,12 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( bool restartEvent; if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); - restartEvent = afterKeyEventLockedInterruptible(connection, - dispatchEntry, keyEntry, handled); + restartEvent = + afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled); } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry); - restartEvent = afterMotionEventLockedInterruptible(connection, - dispatchEntry, motionEntry, handled); + restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, + motionEntry, handled); } else { restartEvent = false; } @@ -4266,7 +4226,8 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( } bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { + DispatchEntry* dispatchEntry, + KeyEntry* keyEntry, bool handled) { if (keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK) { if (!handled) { // Report the key as unhandled, since the fallback was not handled. @@ -4291,9 +4252,9 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // Dispatch the unhandled key to the policy with the cancel flag. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to cancel fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, + keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); @@ -4301,8 +4262,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con mLock.unlock(); - mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), - &event, keyEntry->policyFlags, &event); + mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), &event, + keyEntry->policyFlags, &event); mLock.lock(); @@ -4321,15 +4282,13 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // If the application did not handle a non-fallback key, first check // that we are in a good state to perform unhandled key event processing // Then ask the policy what to do with it. - bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN - && keyEntry->repeatCount == 0; + bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN && keyEntry->repeatCount == 0; if (fallbackKeyCode == -1 && !initialDown) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Skipping unhandled key event processing " - "since this is not an initial down. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - originalKeyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); + "since this is not an initial down. " + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + originalKeyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif return false; } @@ -4337,17 +4296,16 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // Dispatch the unhandled key to the policy. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to perform fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); + "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); mLock.unlock(); - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), - &event, keyEntry->policyFlags, &event); + bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(), &event, + keyEntry->policyFlags, &event); mLock.lock(); @@ -4372,19 +4330,19 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // Cancel the fallback key if the policy decides not to send it anymore. // We will continue to dispatch the key to the policy but we will no // longer dispatch a fallback key to the application. - if (fallbackKeyCode != AKEYCODE_UNKNOWN - && (!fallback || fallbackKeyCode != event.getKeyCode())) { + if (fallbackKeyCode != AKEYCODE_UNKNOWN && + (!fallback || fallbackKeyCode != event.getKeyCode())) { #if DEBUG_OUTBOUND_EVENT_DETAILS if (fallback) { ALOGD("Unhandled key event: Policy requested to send key %d" - "as a fallback for %d, but on the DOWN it had requested " - "to send %d instead. Fallback canceled.", - event.getKeyCode(), originalKeyCode, fallbackKeyCode); + "as a fallback for %d, but on the DOWN it had requested " + "to send %d instead. Fallback canceled.", + event.getKeyCode(), originalKeyCode, fallbackKeyCode); } else { ALOGD("Unhandled key event: Policy did not request fallback for %d, " - "but on the DOWN it had requested to send %d. " - "Fallback canceled.", - originalKeyCode, fallbackKeyCode); + "but on the DOWN it had requested to send %d. " + "Fallback canceled.", + originalKeyCode, fallbackKeyCode); } #endif @@ -4396,8 +4354,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con fallback = false; fallbackKeyCode = AKEYCODE_UNKNOWN; if (keyEntry->action != AKEY_EVENT_ACTION_UP) { - connection->inputState.setFallbackKey(originalKeyCode, - fallbackKeyCode); + connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); } } @@ -4407,11 +4364,10 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con const KeyedVector<int32_t, int32_t>& fallbackKeys = connection->inputState.getFallbackKeys(); for (size_t i = 0; i < fallbackKeys.size(); i++) { - msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), - fallbackKeys.valueAt(i)); + msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i)); } ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.", - fallbackKeys.size(), msg.c_str()); + fallbackKeys.size(), msg.c_str()); } #endif @@ -4431,8 +4387,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Dispatching fallback key. " - "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", - originalKeyCode, fallbackKeyCode, keyEntry->metaState); + "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", + originalKeyCode, fallbackKeyCode, keyEntry->metaState); #endif return true; // restart the event } else { @@ -4448,7 +4404,8 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con } bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { + DispatchEntry* dispatchEntry, + MotionEntry* motionEntry, bool handled) { return false; } @@ -4462,12 +4419,13 @@ void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* comman void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { event->initialize(entry->deviceId, entry->source, entry->displayId, entry->action, entry->flags, - entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, - entry->downTime, entry->eventTime); + entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, + entry->downTime, entry->eventTime); } void InputDispatcher::updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { + int32_t injectionResult, + nsecs_t timeSpentWaitingForApplication) { // TODO Write some statistics about how long we spend waiting. } @@ -4512,780 +4470,4 @@ void InputDispatcher::monitor() { 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, 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), - 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, pointers=[", - deviceId, source, displayId, motionActionToString(action).c_str(), actionButton, flags, - metaState, buttonState, motionClassificationToString(classification), edgeFlags, - xPrecision, yPrecision); - - 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.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.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"; - } -} - -InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) { - for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) { - if (entry->seq == seq) { - return entry; - } - } - return nullptr; -} - -// --- 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 new file mode 100644 index 0000000000..67bf199cd0 --- /dev/null +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2010 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_DISPATCHER_H +#define _UI_INPUT_DISPATCHER_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 "Queue.h" +#include "TouchState.h" +#include "TouchedWindow.h" + +#include <cutils/atomic.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 <InputListener.h> +#include <InputReporterInterface.h> + +namespace android::inputdispatcher { + +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. + * + * IMPORTANT INVARIANT: + * Because the policy can potentially block or cause re-entrance into the input dispatcher, + * the input dispatcher never calls into the policy while holding its internal locks. + * The implementation is also carefully designed to recover from scenarios such as an + * input channel becoming unregistered while identifying input targets or processing timeouts. + * + * Methods marked 'Locked' must be called with the lock acquired. + * + * Methods marked 'LockedInterruptible' must be called with the lock acquired but + * may during the course of their execution release the lock, call into the policy, and + * then reacquire the lock. The caller is responsible for recovering gracefully. + * + * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. + */ +class InputDispatcher : public android::InputDispatcherInterface { +protected: + virtual ~InputDispatcher(); + +public: + explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); + + virtual void dump(std::string& dump) override; + virtual void monitor() override; + + virtual void dispatchOnce() override; + + virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; + virtual void notifyKey(const NotifyKeyArgs* args) override; + virtual void notifyMotion(const NotifyMotionArgs* args) override; + virtual void notifySwitch(const NotifySwitchArgs* args) override; + virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; + + virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, + int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, + uint32_t policyFlags) override; + + virtual void setInputWindows( + const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId, + const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override; + virtual void setFocusedApplication( + int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) override; + virtual void setFocusedDisplay(int32_t displayId) override; + virtual void setInputDispatchMode(bool enabled, bool frozen) override; + virtual void setInputFilterEnabled(bool enabled) override; + + virtual bool transferTouchFocus(const sp<IBinder>& fromToken, + const sp<IBinder>& toToken) override; + + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, + int32_t displayId) override; + virtual status_t registerInputMonitor(const sp<InputChannel>& inputChannel, int32_t displayId, + bool isGestureMonitor) override; + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) override; + virtual status_t pilferPointers(const sp<IBinder>& token) override; + +private: + + enum DropReason { + DROP_REASON_NOT_DROPPED = 0, + DROP_REASON_POLICY = 1, + DROP_REASON_APP_SWITCH = 2, + DROP_REASON_DISABLED = 3, + DROP_REASON_BLOCKED = 4, + DROP_REASON_STALE = 5, + }; + + sp<InputDispatcherPolicyInterface> mPolicy; + android::InputDispatcherConfiguration mConfig; + + std::mutex mLock; + + std::condition_variable mDispatcherIsAlive; + + sp<Looper> mLooper; + + EventEntry* mPendingEvent GUARDED_BY(mLock); + Queue<EventEntry> mInboundQueue GUARDED_BY(mLock); + Queue<EventEntry> mRecentQueue GUARDED_BY(mLock); + Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock); + + DropReason mLastDropReason GUARDED_BY(mLock); + + void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) REQUIRES(mLock); + + // Enqueues an inbound event. Returns true if mLooper->wake() should be called. + bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock); + + // Cleans up input state when dropping an inbound event. + void dropInboundEventLocked(EventEntry* entry, DropReason dropReason) REQUIRES(mLock); + + // Adds an event to a queue of recent events for debugging purposes. + void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock); + + // App switch latency optimization. + bool mAppSwitchSawKeyDown GUARDED_BY(mLock); + nsecs_t mAppSwitchDueTime GUARDED_BY(mLock); + + bool isAppSwitchKeyEvent(KeyEntry* keyEntry); + bool isAppSwitchPendingLocked() REQUIRES(mLock); + void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock); + + // Stale event latency optimization. + static bool isStaleEvent(nsecs_t currentTime, EventEntry* entry); + + // Blocked event latency optimization. Drops old events when the user intends + // to transfer focus to a new application. + EventEntry* mNextUnblockedEvent GUARDED_BY(mLock); + + sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, + bool addOutsideTargets = false, + bool addPortalWindows = false) REQUIRES(mLock); + + // All registered connections mapped by channel file descriptor. + KeyedVector<int, sp<Connection>> mConnectionsByFd GUARDED_BY(mLock); + + struct IBinderHash { + std::size_t operator()(const sp<IBinder>& b) const { + return std::hash<IBinder*>{}(b.get()); + } + }; + std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken + GUARDED_BY(mLock); + + // Finds the display ID of the gesture monitor identified by the provided token. + std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token) + REQUIRES(mLock); + + ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); + + // Input channels that will receive a copy of all input events sent to the provided display. + std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay GUARDED_BY(mLock); + + // Input channels that will receive pointer events that start within the corresponding display. + // These are a bit special when compared to global monitors since they'll cause gesture streams + // to continue even when there isn't a touched window,and have the ability to steal the rest of + // the pointer stream in order to claim it for a system gesture. + std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay GUARDED_BY(mLock); + + // Event injection and synchronization. + std::condition_variable mInjectionResultAvailable; + bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); + void setInjectionResult(EventEntry* entry, int32_t injectionResult); + + std::condition_variable mInjectionSyncFinished; + void incrementPendingForegroundDispatches(EventEntry* entry); + void decrementPendingForegroundDispatches(EventEntry* entry); + + // Key repeat tracking. + struct KeyRepeatState { + KeyEntry* lastKeyEntry; // or null if no repeat + nsecs_t nextRepeatTime; + } mKeyRepeatState GUARDED_BY(mLock); + + void resetKeyRepeatLocked() REQUIRES(mLock); + KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock); + + // Key replacement tracking + struct KeyReplacement { + int32_t keyCode; + int32_t deviceId; + bool operator==(const KeyReplacement& rhs) const { + return keyCode == rhs.keyCode && deviceId == rhs.deviceId; + } + bool operator<(const KeyReplacement& rhs) const { + return keyCode != rhs.keyCode ? keyCode < rhs.keyCode : deviceId < rhs.deviceId; + } + }; + // Maps the key code replaced, device id tuple to the key code it was replaced with + KeyedVector<KeyReplacement, int32_t> mReplacedKeys GUARDED_BY(mLock); + // Process certain Meta + Key combinations + void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action, int32_t& keyCode, + int32_t& metaState); + + // Deferred command processing. + bool haveCommandsLocked() const REQUIRES(mLock); + bool runCommandsLockedInterruptible() REQUIRES(mLock); + CommandEntry* postCommandLocked(Command command) REQUIRES(mLock); + + // Input filter processing. + bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock); + bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) REQUIRES(mLock); + + // Inbound event processing. + void drainInboundQueueLocked() REQUIRES(mLock); + void releasePendingEventLocked() REQUIRES(mLock); + void releaseInboundEventLocked(EventEntry* entry) REQUIRES(mLock); + + // Dispatch state. + bool mDispatchEnabled GUARDED_BY(mLock); + bool mDispatchFrozen GUARDED_BY(mLock); + bool mInputFilterEnabled GUARDED_BY(mLock); + + std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay + GUARDED_BY(mLock); + // Get window handles by display, return an empty vector if not found. + std::vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const + REQUIRES(mLock); + sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const + REQUIRES(mLock); + sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock); + bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); + + // Focus tracking for keys, trackball, etc. + std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay + GUARDED_BY(mLock); + + KeyedVector<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock); + TouchState mTempTouchState GUARDED_BY(mLock); + + // Focused applications. + std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay + GUARDED_BY(mLock); + + // Top focused display. + int32_t mFocusedDisplayId GUARDED_BY(mLock); + + // Dispatcher state at time of last ANR. + std::string mLastANRState GUARDED_BY(mLock); + + // Dispatch inbound events. + bool dispatchConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry) + REQUIRES(mLock); + bool dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) REQUIRES(mLock); + bool dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, + nsecs_t* nextWakeupTime) REQUIRES(mLock); + bool dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, + nsecs_t* nextWakeupTime) REQUIRES(mLock); + void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, + const std::vector<InputTarget>& inputTargets) REQUIRES(mLock); + + void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry); + void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry); + + // Keeping track of ANR timeouts. + enum InputTargetWaitCause { + INPUT_TARGET_WAIT_CAUSE_NONE, + INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, + INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, + }; + + InputTargetWaitCause mInputTargetWaitCause GUARDED_BY(mLock); + nsecs_t mInputTargetWaitStartTime GUARDED_BY(mLock); + nsecs_t mInputTargetWaitTimeoutTime GUARDED_BY(mLock); + bool mInputTargetWaitTimeoutExpired GUARDED_BY(mLock); + sp<IBinder> mInputTargetWaitApplicationToken GUARDED_BY(mLock); + + // Contains the last window which received a hover event. + sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock); + + // Finding targets for input events. + int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, + const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, + nsecs_t* nextWakeupTime, const char* reason) + REQUIRES(mLock); + + void removeWindowByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock); + + void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, + const sp<InputChannel>& inputChannel) + REQUIRES(mLock); + nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock); + void resetANRTimeoutsLocked() REQUIRES(mLock); + + int32_t getTargetDisplayId(const EventEntry* entry); + int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, + std::vector<InputTarget>& inputTargets, + nsecs_t* nextWakeupTime) REQUIRES(mLock); + int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, + std::vector<InputTarget>& inputTargets, + nsecs_t* nextWakeupTime, + bool* outConflictingPointerActions) REQUIRES(mLock); + std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked( + int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) + REQUIRES(mLock); + void addGestureMonitors(const std::vector<Monitor>& monitors, + std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0, + float yOffset = 0); + + void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, + BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) + REQUIRES(mLock); + void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset, + std::vector<InputTarget>& inputTargets) REQUIRES(mLock); + void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId, + float xOffset = 0, float yOffset = 0) REQUIRES(mLock); + + void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock); + bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, + const InjectionState* injectionState); + bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x, + int32_t y) const REQUIRES(mLock); + bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock); + std::string getApplicationWindowLabel(const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle); + + std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime, + const sp<InputWindowHandle>& windowHandle, + const EventEntry* eventEntry, + const char* targetType) REQUIRES(mLock); + + // Manage the dispatch cycle for a single connection. + // These methods are deliberately not Interruptible because doing all of the work + // with the mutex held makes it easier to ensure that connection invariants are maintained. + // If needed, the methods post commands to run later once the critical bits are done. + void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, + EventEntry* eventEntry, const InputTarget* inputTarget) + REQUIRES(mLock); + void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, + EventEntry* eventEntry, const InputTarget* inputTarget) + REQUIRES(mLock); + void enqueueDispatchEntryLocked(const sp<Connection>& connection, EventEntry* eventEntry, + const InputTarget* inputTarget, int32_t dispatchMode) + REQUIRES(mLock); + void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) + REQUIRES(mLock); + void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, + uint32_t seq, bool handled) REQUIRES(mLock); + void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, + bool notify) REQUIRES(mLock); + void drainDispatchQueue(Queue<DispatchEntry>* queue); + void releaseDispatchEntry(DispatchEntry* dispatchEntry); + static int handleReceiveCallback(int fd, int events, void* data); + // The action sent should only be of type AMOTION_EVENT_* + void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, + const sp<IBinder>& newToken) REQUIRES(mLock); + + void synthesizeCancelationEventsForAllConnectionsLocked(const CancelationOptions& options) + REQUIRES(mLock); + void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options) + REQUIRES(mLock); + void synthesizeCancelationEventsForMonitorsLocked( + const CancelationOptions& options, + std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock); + void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, + const CancelationOptions& options) + REQUIRES(mLock); + void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, + const CancelationOptions& options) + REQUIRES(mLock); + + // Splitting motion events across windows. + MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); + + // Reset and drop everything the dispatcher is doing. + void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock); + + // Dump state. + void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock); + void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors); + void logDispatchStateLocked() REQUIRES(mLock); + + // Registration. + void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock); + void removeMonitorChannelLocked( + const sp<InputChannel>& inputChannel, + std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock); + status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify) + REQUIRES(mLock); + + // Interesting events that we might like to log or tell the framework about. + void onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection, + uint32_t seq, bool handled) REQUIRES(mLock); + void onDispatchCycleBrokenLocked(nsecs_t currentTime, const sp<Connection>& connection) + REQUIRES(mLock); + void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus, + const sp<InputWindowHandle>& newFocus) REQUIRES(mLock); + void onANRLocked(nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, + const sp<InputWindowHandle>& windowHandle, nsecs_t eventTime, + nsecs_t waitStartTime, const char* reason) REQUIRES(mLock); + + // Outbound policy interactions. + void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) + REQUIRES(mLock); + void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void doNotifyANRLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry) + REQUIRES(mLock); + void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, + DispatchEntry* dispatchEntry, KeyEntry* keyEntry, + bool handled) REQUIRES(mLock); + bool afterMotionEventLockedInterruptible(const sp<Connection>& connection, + DispatchEntry* dispatchEntry, MotionEntry* motionEntry, + bool handled) REQUIRES(mLock); + void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); + void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); + + // Statistics gathering. + void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry, + int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); + void traceInboundQueueLengthLocked() REQUIRES(mLock); + void traceOutboundQueueLength(const sp<Connection>& connection); + void traceWaitQueueLength(const sp<Connection>& connection); + + sp<InputReporterInterface> mReporter; +}; + +} // 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 0000000000..8d7fa7573b --- /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 0000000000..18b1b8c10a --- /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 0000000000..7d9b03a70e --- /dev/null +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -0,0 +1,370 @@ +/* + * 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.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.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 0000000000..205b64728a --- /dev/null +++ b/services/inputflinger/dispatcher/InputState.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_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; + 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 0000000000..80fa2cb995 --- /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 0000000000..5acf92b1b1 --- /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 0000000000..289b0848bf --- /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 0000000000..b67c9eb507 --- /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/Queue.h b/services/inputflinger/dispatcher/Queue.h new file mode 100644 index 0000000000..0e75821661 --- /dev/null +++ b/services/inputflinger/dispatcher/Queue.h @@ -0,0 +1,88 @@ +/* + * 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_QUEUE_H +#define _UI_INPUT_INPUTDISPATCHER_QUEUE_H + +namespace android::inputdispatcher { + +// Generic queue implementation. +template <typename T> +struct Queue { + T* head; + T* tail; + uint32_t entryCount; + + inline Queue() : head(nullptr), tail(nullptr), entryCount(0) {} + + inline bool isEmpty() const { return !head; } + + inline void enqueueAtTail(T* entry) { + entryCount++; + entry->prev = tail; + if (tail) { + tail->next = entry; + } else { + head = entry; + } + entry->next = nullptr; + tail = entry; + } + + inline void enqueueAtHead(T* entry) { + entryCount++; + entry->next = head; + if (head) { + head->prev = entry; + } else { + tail = entry; + } + entry->prev = nullptr; + head = entry; + } + + inline void dequeue(T* entry) { + entryCount--; + if (entry->prev) { + entry->prev->next = entry->next; + } else { + head = entry->next; + } + if (entry->next) { + entry->next->prev = entry->prev; + } else { + tail = entry->prev; + } + } + + inline T* dequeueAtHead() { + entryCount--; + T* entry = head; + head = entry->next; + if (head) { + head->prev = nullptr; + } else { + tail = nullptr; + } + return entry; + } + + uint32_t count() const { return entryCount; } +}; + +} // namespace android::inputdispatcher + +#endif // _UI_INPUT_INPUTDISPATCHER_QUEUE_H diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp new file mode 100644 index 0000000000..18848a0c2f --- /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 0000000000..3e0e0eb897 --- /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 0000000000..8713aa3f56 --- /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 0000000000..00abf47cd2 --- /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 0000000000..a359557f80 --- /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 0000000000..9329ca664e --- /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 0000000000..4214488f04 --- /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 0000000000..2604959656 --- /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/reader/Android.bp b/services/inputflinger/reader/Android.bp new file mode 100644 index 0000000000..4e97397e2b --- /dev/null +++ b/services/inputflinger/reader/Android.bp @@ -0,0 +1,72 @@ +// 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: "libinputreader_headers", + export_include_dirs: [ + "include", + "mapper", + "mapper/accumulator", + ], +} + +cc_library_shared { + name: "libinputreader", + defaults: ["inputflinger_defaults"], + + srcs: [ + "EventHub.cpp", + "InputDevice.cpp", + "mapper/accumulator/CursorButtonAccumulator.cpp", + "mapper/accumulator/CursorScrollAccumulator.cpp", + "mapper/accumulator/SingleTouchMotionAccumulator.cpp", + "mapper/accumulator/TouchButtonAccumulator.cpp", + "mapper/CursorInputMapper.cpp", + "mapper/ExternalStylusInputMapper.cpp", + "mapper/InputMapper.cpp", + "mapper/JoystickInputMapper.cpp", + "mapper/KeyboardInputMapper.cpp", + "mapper/MultiTouchInputMapper.cpp", + "mapper/RotaryEncoderInputMapper.cpp", + "mapper/SingleTouchInputMapper.cpp", + "mapper/SwitchInputMapper.cpp", + "mapper/TouchInputMapper.cpp", + "mapper/VibratorInputMapper.cpp", + "InputReader.cpp", + "InputReaderFactory.cpp", + "TouchVideoDevice.cpp", + ], + + shared_libs: [ + "libbase", + "libinputflinger_base", + "libcrypto", + "libcutils", + "libinput", + "liblog", + "libui", + "libutils", + "libhardware_legacy", + "libstatslog", + ], + + header_libs: [ + "libinputflinger_headers", + "libinputreader_headers", + ], + + export_header_lib_headers: [ + "libinputflinger_headers", + ], +} diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index ce5627271a..a5e5415dd7 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -25,9 +25,9 @@ #include <stdlib.h> #include <string.h> #include <sys/epoll.h> -#include <sys/limits.h> #include <sys/inotify.h> #include <sys/ioctl.h> +#include <sys/limits.h> #include <sys/utsname.h> #include <unistd.h> @@ -42,13 +42,13 @@ #include <android-base/stringprintf.h> #include <cutils/properties.h> #include <openssl/sha.h> +#include <utils/Errors.h> #include <utils/Log.h> #include <utils/Timers.h> #include <utils/threads.h> -#include <utils/Errors.h> -#include <input/KeyLayoutMap.h> #include <input/KeyCharacterMap.h> +#include <input/KeyLayoutMap.h> #include <input/VirtualKeyMap.h> /* this macro is used to tell if "bit" is set in "array" @@ -56,10 +56,10 @@ * operation with a byte that only has the relevant bit set. * eg. to check for the 12th bit, we do (array[1] & 1<<4) */ -#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)%8))) +#define test_bit(bit, array) ((array)[(bit) / 8] & (1 << ((bit) % 8))) /* this macro computes the number of bytes needed to represent a bit array of the specified size */ -#define sizeof_bit_array(bits) (((bits) + 7) / 8) +#define sizeof_bit_array(bits) (((bits) + 7) / 8) #define INDENT " " #define INDENT2 " " @@ -71,10 +71,10 @@ namespace android { static constexpr bool DEBUG = false; -static const char *WAKE_LOCK_ID = "KeyEvents"; -static const char *DEVICE_PATH = "/dev/input"; +static const char* WAKE_LOCK_ID = "KeyEvents"; +static const char* DEVICE_PATH = "/dev/input"; // v4l2 devices go directly into /dev -static const char *VIDEO_DEVICE_PATH = "/dev"; +static const char* VIDEO_DEVICE_PATH = "/dev"; static inline const char* toString(bool value) { return value ? "true" : "false"; @@ -126,7 +126,7 @@ static bool isV4lTouchNode(const char* name) { * directly from /dev. */ static bool isV4lScanningEnabled() { - return property_get_bool("ro.input.video_enabled", true /* default_value */); + return property_get_bool("ro.input.video_enabled", true /* default_value */); } static nsecs_t processEventTimestamp(const struct input_event& event) { @@ -153,27 +153,27 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { // Touch devices get dibs on touch-related axes. if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) { switch (axis) { - case ABS_X: - case ABS_Y: - case ABS_PRESSURE: - case ABS_TOOL_WIDTH: - case ABS_DISTANCE: - case ABS_TILT_X: - case ABS_TILT_Y: - case ABS_MT_SLOT: - case ABS_MT_TOUCH_MAJOR: - case ABS_MT_TOUCH_MINOR: - case ABS_MT_WIDTH_MAJOR: - case ABS_MT_WIDTH_MINOR: - case ABS_MT_ORIENTATION: - case ABS_MT_POSITION_X: - case ABS_MT_POSITION_Y: - case ABS_MT_TOOL_TYPE: - case ABS_MT_BLOB_ID: - case ABS_MT_TRACKING_ID: - case ABS_MT_PRESSURE: - case ABS_MT_DISTANCE: - return INPUT_DEVICE_CLASS_TOUCH; + case ABS_X: + case ABS_Y: + case ABS_PRESSURE: + case ABS_TOOL_WIDTH: + case ABS_DISTANCE: + case ABS_TILT_X: + case ABS_TILT_Y: + case ABS_MT_SLOT: + case ABS_MT_TOUCH_MAJOR: + case ABS_MT_TOUCH_MINOR: + case ABS_MT_WIDTH_MAJOR: + case ABS_MT_WIDTH_MINOR: + case ABS_MT_ORIENTATION: + case ABS_MT_POSITION_X: + case ABS_MT_POSITION_Y: + case ABS_MT_TOOL_TYPE: + case ABS_MT_BLOB_ID: + case ABS_MT_TRACKING_ID: + case ABS_MT_PRESSURE: + case ABS_MT_DISTANCE: + return INPUT_DEVICE_CLASS_TOUCH; } } @@ -191,12 +191,20 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { // --- EventHub::Device --- EventHub::Device::Device(int fd, int32_t id, const std::string& path, - const InputDeviceIdentifier& identifier) : - next(nullptr), - fd(fd), id(id), path(path), identifier(identifier), - classes(0), configuration(nullptr), virtualKeyMap(nullptr), - ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0), - enabled(true), isVirtual(fd < 0) { + const InputDeviceIdentifier& identifier) + : next(nullptr), + fd(fd), + id(id), + path(path), + identifier(identifier), + classes(0), + configuration(nullptr), + virtualKeyMap(nullptr), + ffEffectPlaying(false), + ffEffectId(-1), + controllerNumber(0), + enabled(true), + isVirtual(fd < 0) { memset(keyBitmask, 0, sizeof(keyBitmask)); memset(absBitmask, 0, sizeof(absBitmask)); memset(relBitmask, 0, sizeof(relBitmask)); @@ -220,7 +228,7 @@ void EventHub::Device::close() { status_t EventHub::Device::enable() { fd = open(path.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK); - if(fd < 0) { + if (fd < 0) { ALOGE("could not open %s, %s\n", path.c_str(), strerror(errno)); return -errno; } @@ -242,12 +250,18 @@ bool EventHub::Device::hasValidFd() { const int EventHub::EPOLL_MAX_EVENTS; -EventHub::EventHub(void) : - mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(), - mOpeningDevices(nullptr), mClosingDevices(nullptr), +EventHub::EventHub(void) + : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), + mNextDeviceId(1), + mControllerNumbers(), + mOpeningDevices(nullptr), + mClosingDevices(nullptr), mNeedToSendFinishedDeviceScan(false), - mNeedToReopenDevices(false), mNeedToScanDevices(true), - mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { + mNeedToReopenDevices(false), + mNeedToScanDevices(true), + mPendingEventCount(0), + mPendingEventIndex(0), + mPendingINotify(false) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mEpollFd = epoll_create1(EPOLL_CLOEXEC); @@ -255,12 +269,12 @@ EventHub::EventHub(void) : mINotifyFd = inotify_init(); mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); - LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", - DEVICE_PATH, strerror(errno)); + LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH, + strerror(errno)); if (isV4lScanningEnabled()) { mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE); LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s", - VIDEO_DEVICE_PATH, strerror(errno)); + VIDEO_DEVICE_PATH, strerror(errno)); } else { mVideoWd = -1; ALOGI("Video device scanning disabled"); @@ -282,16 +296,16 @@ EventHub::EventHub(void) : result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", - errno); + errno); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", - errno); + errno); eventItem.data.fd = mWakeReadPipeFd; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", - errno); + errno); int major, minor; getLinuxRelease(&major, &minor); @@ -348,7 +362,7 @@ void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) } status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const { + RawAbsoluteAxisInfo* outAxisInfo) const { outAxisInfo->clear(); if (axis >= 0 && axis <= ABS_MAX) { @@ -357,9 +371,9 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, Device* device = getDeviceLocked(deviceId); if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", - axis, device->identifier.name.c_str(), device->fd, errno); + if (ioctl(device->fd, EVIOCGABS(axis), &info)) { + ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, + device->identifier.name.c_str(), device->fd, errno); return -errno; } @@ -466,9 +480,9 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* Device* device = getDeviceLocked(deviceId); if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", - axis, device->identifier.name.c_str(), device->fd, errno); + if (ioctl(device->fd, EVIOCGABS(axis), &info)) { + ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, + device->identifier.name.c_str(), device->fd, errno); return -errno; } @@ -479,8 +493,8 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* return -1; } -bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const { +bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); @@ -489,9 +503,9 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { scanCodes.clear(); - status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey( - keyCodes[codeIndex], &scanCodes); - if (! err) { + status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex], + &scanCodes); + if (!err) { // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver for (size_t sc = 0; sc < scanCodes.size(); sc++) { @@ -507,9 +521,8 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, return false; } -status_t EventHub::mapKey(int32_t deviceId, - int32_t scanCode, int32_t usageCode, int32_t metaState, - int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const { +status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, + int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); status_t status = NAME_NOT_FOUND; @@ -616,7 +629,7 @@ void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) { } void EventHub::getVirtualKeyDefinitions(int32_t deviceId, - std::vector<VirtualKeyDefinition>& outVirtualKeys) const { + std::vector<VirtualKeyDefinition>& outVirtualKeys) const { outVirtualKeys.clear(); AutoMutex _l(mLock); @@ -637,15 +650,13 @@ sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const { return nullptr; } -bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, - const sp<KeyCharacterMap>& map) { +bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { if (map != device->overlayKeyMap) { device->overlayKeyMap = map; - device->combinedKeyMap = KeyCharacterMap::combine( - device->keyMap.keyCharacterMap, map); + device->combinedKeyMap = KeyCharacterMap::combine(device->keyMap.keyCharacterMap, map); return true; } } @@ -654,8 +665,7 @@ bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, static std::string generateDescriptor(InputDeviceIdentifier& identifier) { std::string rawDescriptor; - rawDescriptor += StringPrintf(":%04x:%04x:", identifier.vendor, - identifier.product); + rawDescriptor += StringPrintf(":%04x:%04x:", identifier.vendor, identifier.product); // TODO add handling for USB devices to not uniqueify kbs that show up twice if (!identifier.uniqueId.empty()) { rawDescriptor += "uniqueId:"; @@ -694,13 +704,13 @@ void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) { if (identifier.uniqueId.empty()) { // If it didn't have a unique id check for conflicts and enforce // uniqueness if necessary. - while(getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) { + while (getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) { identifier.nonce++; rawDescriptor = generateDescriptor(identifier); } } ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.c_str(), - identifier.descriptor.c_str()); + identifier.descriptor.c_str()); } void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { @@ -717,7 +727,7 @@ void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { effect.replay.delay = 0; if (ioctl(device->fd, EVIOCSFF, &effect)) { ALOGW("Could not upload force feedback effect to device %s due to error %d.", - device->identifier.name.c_str(), errno); + device->identifier.name.c_str(), errno); return; } device->ffEffectId = effect.id; @@ -730,7 +740,7 @@ void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { ev.value = 1; if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { ALOGW("Could not start force feedback effect on device %s due to error %d.", - device->identifier.name.c_str(), errno); + device->identifier.name.c_str(), errno); return; } device->ffEffectPlaying = true; @@ -752,7 +762,7 @@ void EventHub::cancelVibrate(int32_t deviceId) { ev.value = 0; if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { ALOGW("Could not stop force feedback effect on device %s due to error %d.", - device->identifier.name.c_str(), errno); + device->identifier.name.c_str(), errno); return; } } @@ -839,12 +849,12 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz // Report any devices that had last been added/removed. while (mClosingDevices) { Device* device = mClosingDevices; - ALOGV("Reporting device closed: id=%d, name=%s\n", - device->id, device->path.c_str()); + ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str()); mClosingDevices = device->next; event->when = now; - event->deviceId = (device->id == mBuiltInKeyboardId) ? - ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID : device->id; + event->deviceId = (device->id == mBuiltInKeyboardId) + ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID + : device->id; event->type = DEVICE_REMOVED; event += 1; delete device; @@ -862,8 +872,7 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz while (mOpeningDevices != nullptr) { Device* device = mOpeningDevices; - ALOGV("Reporting device opened: id=%d, name=%s\n", - device->id, device->path.c_str()); + ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str()); mOpeningDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; @@ -909,15 +918,15 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); } else { ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.", - eventItem.events); + eventItem.events); } continue; } Device* device = getDeviceByFdLocked(eventItem.data.fd); if (!device) { - ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", - eventItem.events, eventItem.data.fd); + ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events, + eventItem.data.fd); ALOG_ASSERT(!DEBUG); continue; } @@ -926,30 +935,30 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz size_t numFrames = device->videoDevice->readAndQueueFrames(); if (numFrames == 0) { ALOGE("Received epoll event for video device %s, but could not read frame", - device->videoDevice->getName().c_str()); + device->videoDevice->getName().c_str()); } } else if (eventItem.events & EPOLLHUP) { // TODO(b/121395353) - consider adding EPOLLRDHUP ALOGI("Removing video device %s due to epoll hang-up event.", - device->videoDevice->getName().c_str()); + device->videoDevice->getName().c_str()); unregisterVideoDeviceFromEpollLocked(*device->videoDevice); device->videoDevice = nullptr; } else { - ALOGW("Received unexpected epoll event 0x%08x for device %s.", - eventItem.events, device->videoDevice->getName().c_str()); + ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events, + device->videoDevice->getName().c_str()); ALOG_ASSERT(!DEBUG); } continue; } // This must be an input event if (eventItem.events & EPOLLIN) { - int32_t readSize = read(device->fd, readBuffer, - sizeof(struct input_event) * capacity); + int32_t readSize = + read(device->fd, readBuffer, sizeof(struct input_event) * capacity); if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { // Device was removed before INotify noticed. ALOGW("could not get event, removed? (fd: %d size: %" PRId32 - " bufferSize: %zu capacity: %zu errno: %d)\n", - device->fd, readSize, bufferSize, capacity, errno); + " bufferSize: %zu capacity: %zu errno: %d)\n", + device->fd, readSize, bufferSize, capacity, errno); deviceChanged = true; closeDeviceLocked(device); } else if (readSize < 0) { @@ -981,12 +990,12 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz } } else if (eventItem.events & EPOLLHUP) { ALOGI("Removing device %s due to epoll hang-up event.", - device->identifier.name.c_str()); + device->identifier.name.c_str()); deviceChanged = true; closeDeviceLocked(device); } else { - ALOGW("Received unexpected epoll event 0x%08x for device %s.", - eventItem.events, device->identifier.name.c_str()); + ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events, + device->identifier.name.c_str()); } } @@ -1081,7 +1090,7 @@ void EventHub::wake() { void EventHub::scanDevicesLocked() { status_t result = scanDirLocked(DEVICE_PATH); - if(result < 0) { + if (result < 0) { ALOGE("scan dir failed for %s", DEVICE_PATH); } if (isV4lScanningEnabled()) { @@ -1109,12 +1118,12 @@ static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint3 } static const int32_t GAMEPAD_KEYCODES[] = { - AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, - AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, - AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, - AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, - AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, - AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, + AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, // + AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, // + AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, // + AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, // + AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, // + AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, // }; status_t EventHub::registerFdForEpoll(int fd) { @@ -1181,7 +1190,7 @@ void EventHub::unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& vide status_t result = unregisterFdFromEpoll(videoDevice.getFd()); if (result != OK) { ALOGW("Could not remove video device fd from epoll for device: %s", - videoDevice.getName().c_str()); + videoDevice.getName().c_str()); } } } @@ -1192,7 +1201,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { ALOGV("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK); - if(fd < 0) { + if (fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } @@ -1200,7 +1209,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { InputDeviceIdentifier identifier; // Get device name. - if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { + if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; @@ -1219,7 +1228,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // Get device driver version. int driverVersion; - if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { + if (ioctl(fd, EVIOCGVERSION, &driverVersion)) { ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; @@ -1227,7 +1236,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // Get device identifier. struct input_id inputId; - if(ioctl(fd, EVIOCGID, &inputId)) { + if (ioctl(fd, EVIOCGID, &inputId)) { ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; @@ -1238,16 +1247,16 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { identifier.version = inputId.version; // Get device physical location. - if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); + if (ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { + // fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.location = buffer; } // Get device unique id. - if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); + if (ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { + // fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.uniqueId = buffer; @@ -1262,16 +1271,16 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { ALOGV("add device %d: %s\n", deviceId, devicePath); ALOGV(" bus: %04x\n" - " vendor %04x\n" - " product %04x\n" - " version %04x\n", - identifier.bus, identifier.vendor, identifier.product, identifier.version); + " vendor %04x\n" + " product %04x\n" + " version %04x\n", + identifier.bus, identifier.vendor, identifier.product, identifier.version); ALOGV(" name: \"%s\"\n", identifier.name.c_str()); ALOGV(" location: \"%s\"\n", identifier.location.c_str()); ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.c_str()); ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.c_str()); - ALOGV(" driver: v%d.%d.%d\n", - driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); + ALOGV(" driver: v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff, + driverVersion & 0xff); // Load the configuration file for the device. loadConfigurationLocked(device); @@ -1287,21 +1296,21 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. - bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) - || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), - sizeof_bit_array(KEY_MAX + 1)); + bool haveKeyboardKeys = + containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) || + containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), + sizeof_bit_array(KEY_MAX + 1)); bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), - sizeof_bit_array(BTN_MOUSE)) - || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), - sizeof_bit_array(BTN_DIGI)); + sizeof_bit_array(BTN_MOUSE)) || + containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), + sizeof_bit_array(BTN_DIGI)); if (haveKeyboardKeys || haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } // See if this is a cursor device such as a trackball or mouse. - if (test_bit(BTN_MOUSE, device->keyBitmask) - && test_bit(REL_X, device->relBitmask) - && test_bit(REL_Y, device->relBitmask)) { + if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && + test_bit(REL_Y, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CURSOR; } @@ -1309,31 +1318,29 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { String8 deviceType = String8(); if (device->configuration && device->configuration->tryGetProperty(String8("device.type"), deviceType)) { - if (!deviceType.compare(String8("rotaryEncoder"))) { - device->classes |= INPUT_DEVICE_CLASS_ROTARY_ENCODER; - } + if (!deviceType.compare(String8("rotaryEncoder"))) { + device->classes |= INPUT_DEVICE_CLASS_ROTARY_ENCODER; + } } // See if this is a touch pad. // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_POSITION_X, device->absBitmask) - && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { + if (test_bit(ABS_MT_POSITION_X, device->absBitmask) && + test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { // Some joysticks such as the PS3 controller report axes that conflict // with the ABS_MT range. Try to confirm that the device really is // a touch screen. if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; } - // Is this an old style single-touch driver? - } else if (test_bit(BTN_TOUCH, device->keyBitmask) - && test_bit(ABS_X, device->absBitmask) - && test_bit(ABS_Y, device->absBitmask)) { + // Is this an old style single-touch driver? + } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) && + test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; - // Is this a BT stylus? + // Is this a BT stylus? } else if ((test_bit(ABS_PRESSURE, device->absBitmask) || - test_bit(BTN_TOUCH, device->keyBitmask)) - && !test_bit(ABS_X, device->absBitmask) - && !test_bit(ABS_Y, device->absBitmask)) { + test_bit(BTN_TOUCH, device->keyBitmask)) && + !test_bit(ABS_X, device->absBitmask) && !test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; // Keyboard will try to claim some of the buttons but we really want to reserve those so we // can fuse it with the touch screen data, so just take them back. Note this means an @@ -1347,8 +1354,8 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { if (haveGamepadButtons) { uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; for (int i = 0; i <= ABS_MAX; i++) { - if (test_bit(i, device->absBitmask) - && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { + if (test_bit(i, device->absBitmask) && + (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { device->classes = assumedClasses; break; } @@ -1389,10 +1396,8 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // Configure the keyboard, gamepad or virtual keyboard. if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { // Register the keyboard as a built-in keyboard if it is eligible. - if (!keyMapStatus - && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD - && isEligibleBuiltInKeyboard(device->identifier, - device->configuration, &device->keyMap)) { + if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD && + isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) { mBuiltInKeyboardId = device->id; } @@ -1403,15 +1408,15 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && - hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && - hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { + hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && + hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && + hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && + hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. - for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { + for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES) / sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; @@ -1421,8 +1426,8 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { - ALOGV("Dropping device: id=%d, path='%s', name='%s'", - deviceId, devicePath, device->identifier.name.c_str()); + ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath, + device->identifier.name.c_str()); delete device; return -1; } @@ -1437,8 +1442,8 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; } - if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD) - && device->classes & INPUT_DEVICE_CLASS_GAMEPAD) { + if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD) && + device->classes & INPUT_DEVICE_CLASS_GAMEPAD) { device->controllerNumber = getNextControllerNumberLocked(device); setLedForControllerLocked(device); } @@ -1451,10 +1456,12 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { break; } } - mUnattachedVideoDevices.erase(std::remove_if(mUnattachedVideoDevices.begin(), - mUnattachedVideoDevices.end(), - [](const std::unique_ptr<TouchVideoDevice>& videoDevice){ - return videoDevice == nullptr; }), mUnattachedVideoDevices.end()); + mUnattachedVideoDevices + .erase(std::remove_if(mUnattachedVideoDevices.begin(), mUnattachedVideoDevices.end(), + [](const std::unique_ptr<TouchVideoDevice>& videoDevice) { + return videoDevice == nullptr; + }), + mUnattachedVideoDevices.end()); if (registerDeviceForEpollLocked(device) != OK) { delete device; @@ -1464,13 +1471,10 @@ status_t EventHub::openDeviceLocked(const char* devicePath) { configureFd(device); ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " - "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ", - deviceId, fd, devicePath, device->identifier.name.c_str(), - device->classes, - device->configurationFile.c_str(), - device->keyMap.keyLayoutFile.c_str(), - device->keyMap.keyCharacterMapFile.c_str(), - toString(mBuiltInKeyboardId == deviceId)); + "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ", + deviceId, fd, devicePath, device->identifier.name.c_str(), device->classes, + device->configurationFile.c_str(), device->keyMap.keyLayoutFile.c_str(), + device->keyMap.keyCharacterMapFile.c_str(), toString(mBuiltInKeyboardId == deviceId)); addDeviceLocked(device); return OK; @@ -1482,8 +1486,8 @@ void EventHub::configureFd(Device* device) { // Disable kernel key repeat since we handle it ourselves unsigned int repeatRate[] = {0, 0}; if (ioctl(device->fd, EVIOCSREP, repeatRate)) { - ALOGW("Unable to disable kernel key repeat for %s: %s", - device->path.c_str(), strerror(errno)); + ALOGW("Unable to disable kernel key repeat for %s: %s", device->path.c_str(), + strerror(errno)); } } @@ -1507,8 +1511,7 @@ void EventHub::configureFd(Device* device) { // clock. int clockId = CLOCK_MONOTONIC; bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId); - ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(), - toString(usingClockIoctl)); + ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(), toString(usingClockIoctl)); } void EventHub::openVideoDeviceLocked(const std::string& devicePath) { @@ -1532,7 +1535,7 @@ void EventHub::openVideoDeviceLocked(const std::string& devicePath) { // Couldn't find a matching input device, so just add it to a temporary holding queue. // A matching input device may appear later. ALOGI("Adding video device %s to list of unattached video devices", - videoDevice->getName().c_str()); + videoDevice->getName().c_str()); mUnattachedVideoDevices.push_back(std::move(videoDevice)); } @@ -1589,12 +1592,10 @@ void EventHub::createVirtualKeyboardLocked() { identifier.uniqueId = "<virtual>"; assignDescriptorLocked(identifier); - Device* device = new Device(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>", - identifier); - device->classes = INPUT_DEVICE_CLASS_KEYBOARD - | INPUT_DEVICE_CLASS_ALPHAKEY - | INPUT_DEVICE_CLASS_DPAD - | INPUT_DEVICE_CLASS_VIRTUAL; + Device* device = + new Device(-1, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, "<virtual>", identifier); + device->classes = INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY | + INPUT_DEVICE_CLASS_DPAD | INPUT_DEVICE_CLASS_VIRTUAL; loadKeyMapLocked(device); addDeviceLocked(device); } @@ -1610,14 +1611,14 @@ void EventHub::loadConfigurationLocked(Device* device) { device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); if (device->configurationFile.empty()) { ALOGD("No input device configuration file found for device '%s'.", - device->identifier.name.c_str()); + device->identifier.name.c_str()); } else { status_t status = PropertyMap::load(String8(device->configurationFile.c_str()), - &device->configuration); + &device->configuration); if (status) { ALOGE("Error loading input device configuration file for device '%s'. " - "Using default configuration.", - device->identifier.name.c_str()); + "Using default configuration.", + device->identifier.name.c_str()); } } } @@ -1661,7 +1662,7 @@ bool EventHub::deviceHasMicLocked(Device* device) { int32_t EventHub::getNextControllerNumberLocked(Device* device) { if (mControllerNumbers.isFull()) { ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s", - device->identifier.name.c_str()); + device->identifier.name.c_str()); return 0; } // Since the controller number 0 is reserved for non-controllers, translate all numbers up by @@ -1671,7 +1672,7 @@ int32_t EventHub::getNextControllerNumberLocked(Device* device) { void EventHub::releaseControllerNumberLocked(Device* device) { int32_t num = device->controllerNumber; - device->controllerNumber= 0; + device->controllerNumber = 0; if (num == 0) { return; } @@ -1692,7 +1693,7 @@ bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { std::vector<int32_t> scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); const size_t N = scanCodes.size(); - for (size_t i=0; i<N && i<=KEY_MAX; i++) { + for (size_t i = 0; i < N && i <= KEY_MAX; i++) { int32_t sc = scanCodes[i]; if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { return true; @@ -1708,8 +1709,8 @@ status_t EventHub::mapLed(Device* device, int32_t led, int32_t* outScanCode) con } int32_t scanCode; - if(device->keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) { - if(scanCode >= 0 && scanCode <= LED_MAX && test_bit(scanCode, device->ledBitmask)) { + if (device->keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) { + if (scanCode >= 0 && scanCode <= LED_MAX && test_bit(scanCode, device->ledBitmask)) { *outScanCode = scanCode; return NO_ERROR; } @@ -1717,7 +1718,7 @@ status_t EventHub::mapLed(Device* device, int32_t led, int32_t* outScanCode) con return NAME_NOT_FOUND; } -void EventHub::closeDeviceByPathLocked(const char *devicePath) { +void EventHub::closeDeviceByPathLocked(const char* devicePath) { Device* device = getDeviceByPathLocked(devicePath); if (device) { closeDeviceLocked(device); @@ -1742,10 +1743,13 @@ void EventHub::closeVideoDeviceByPathLocked(const std::string& devicePath) { return; } } - mUnattachedVideoDevices.erase(std::remove_if(mUnattachedVideoDevices.begin(), - mUnattachedVideoDevices.end(), [&devicePath]( - const std::unique_ptr<TouchVideoDevice>& videoDevice) { - return videoDevice->getPath() == devicePath; }), mUnattachedVideoDevices.end()); + mUnattachedVideoDevices + .erase(std::remove_if(mUnattachedVideoDevices.begin(), mUnattachedVideoDevices.end(), + [&devicePath]( + const std::unique_ptr<TouchVideoDevice>& videoDevice) { + return videoDevice->getPath() == devicePath; + }), + mUnattachedVideoDevices.end()); } void EventHub::closeAllDevicesLocked() { @@ -1756,13 +1760,12 @@ void EventHub::closeAllDevicesLocked() { } void EventHub::closeDeviceLocked(Device* device) { - ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x", - device->path.c_str(), device->identifier.name.c_str(), device->id, - device->fd, device->classes); + ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x", device->path.c_str(), + device->identifier.name.c_str(), device->id, device->fd, device->classes); if (device->id == mBuiltInKeyboardId) { ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", - device->path.c_str(), mBuiltInKeyboardId); + device->path.c_str(), mBuiltInKeyboardId); mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; } @@ -1780,7 +1783,7 @@ void EventHub::closeDeviceLocked(Device* device) { // Unlink for opening devices list if it is present. Device* pred = nullptr; bool found = false; - for (Device* entry = mOpeningDevices; entry != nullptr; ) { + for (Device* entry = mOpeningDevices; entry != nullptr;) { if (entry == device) { found = true; break; @@ -1812,30 +1815,28 @@ status_t EventHub::readNotifyLocked() { char event_buf[512]; int event_size; int event_pos = 0; - struct inotify_event *event; + struct inotify_event* event; ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd); res = read(mINotifyFd, event_buf, sizeof(event_buf)); - if(res < (int)sizeof(*event)) { - if(errno == EINTR) - return 0; + if (res < (int)sizeof(*event)) { + if (errno == EINTR) return 0; ALOGW("could not get event, %s\n", strerror(errno)); return -1; } - while(res >= (int)sizeof(*event)) { - event = (struct inotify_event *)(event_buf + event_pos); - if(event->len) { + while (res >= (int)sizeof(*event)) { + event = (struct inotify_event*)(event_buf + event_pos); + if (event->len) { if (event->wd == mInputWd) { std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name); - if(event->mask & IN_CREATE) { + if (event->mask & IN_CREATE) { openDeviceLocked(filename.c_str()); } else { ALOGI("Removing device '%s' due to inotify event\n", filename.c_str()); closeDeviceByPathLocked(filename.c_str()); } - } - else if (event->wd == mVideoWd) { + } else if (event->wd == mVideoWd) { if (isV4lTouchNode(event->name)) { std::string filename = StringPrintf("%s/%s", VIDEO_DEVICE_PATH, event->name); if (event->mask & IN_CREATE) { @@ -1845,8 +1846,7 @@ status_t EventHub::readNotifyLocked() { closeVideoDeviceByPathLocked(filename); } } - } - else { + } else { LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd); } } @@ -1857,22 +1857,19 @@ status_t EventHub::readNotifyLocked() { return 0; } -status_t EventHub::scanDirLocked(const char *dirname) -{ +status_t EventHub::scanDirLocked(const char* dirname) { char devname[PATH_MAX]; - char *filename; - DIR *dir; - struct dirent *de; + char* filename; + DIR* dir; + struct dirent* de; dir = opendir(dirname); - if(dir == nullptr) - return -1; + if (dir == nullptr) return -1; strcpy(devname, dirname); filename = devname + strlen(devname); *filename++ = '/'; - while((de = readdir(dir))) { - if(de->d_name[0] == '.' && - (de->d_name[1] == '\0' || - (de->d_name[1] == '.' && de->d_name[2] == '\0'))) + while ((de = readdir(dir))) { + if (de->d_name[0] == '.' && + (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; strcpy(filename, de->d_name); openDeviceLocked(devname); @@ -1884,17 +1881,16 @@ status_t EventHub::scanDirLocked(const char *dirname) /** * Look for all dirname/v4l-touch* devices, and open them. */ -status_t EventHub::scanVideoDirLocked(const std::string& dirname) -{ +status_t EventHub::scanVideoDirLocked(const std::string& dirname) { DIR* dir; struct dirent* de; dir = opendir(dirname.c_str()); - if(!dir) { + if (!dir) { ALOGE("Could not open video directory %s", dirname.c_str()); return BAD_VALUE; } - while((de = readdir(dir))) { + while ((de = readdir(dir))) { const char* name = de->d_name; if (isV4lTouchNode(name)) { ALOGI("Found touch video device %s", name); @@ -1926,10 +1922,10 @@ void EventHub::dump(std::string& dump) { const Device* device = mDevices.valueAt(i); if (mBuiltInKeyboardId == device->id) { dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", - device->id, device->identifier.name.c_str()); + device->id, device->identifier.name.c_str()); } else { dump += StringPrintf(INDENT2 "%d: %s\n", device->id, - device->identifier.name.c_str()); + device->identifier.name.c_str()); } dump += StringPrintf(INDENT3 "Classes: 0x%08x\n", device->classes); dump += StringPrintf(INDENT3 "Path: %s\n", device->path.c_str()); @@ -1939,17 +1935,17 @@ void EventHub::dump(std::string& dump) { dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber); dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.c_str()); dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " - "product=0x%04x, version=0x%04x\n", - device->identifier.bus, device->identifier.vendor, - device->identifier.product, device->identifier.version); + "product=0x%04x, version=0x%04x\n", + device->identifier.bus, device->identifier.vendor, + device->identifier.product, device->identifier.version); dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n", - device->keyMap.keyLayoutFile.c_str()); + device->keyMap.keyLayoutFile.c_str()); dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n", - device->keyMap.keyCharacterMapFile.c_str()); + device->keyMap.keyCharacterMapFile.c_str()); dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n", - device->configurationFile.c_str()); + device->configurationFile.c_str()); dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", - toString(device->overlayKeyMap != nullptr)); + toString(device->overlayKeyMap != nullptr)); dump += INDENT3 "VideoDevice: "; if (device->videoDevice) { dump += device->videoDevice->dump() + "\n"; @@ -1974,5 +1970,4 @@ void EventHub::monitor() { mLock.unlock(); } - }; // namespace android diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp new file mode 100644 index 0000000000..d0613b0c69 --- /dev/null +++ b/services/inputflinger/reader/InputDevice.cpp @@ -0,0 +1,338 @@ +/* + * 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 "Macros.h" + +#include "InputDevice.h" + +#include "InputMapper.h" + +namespace android { + +InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, + int32_t controllerNumber, const InputDeviceIdentifier& identifier, + uint32_t classes) + : mContext(context), + mId(id), + mGeneration(generation), + mControllerNumber(controllerNumber), + mIdentifier(identifier), + mClasses(classes), + mSources(0), + mIsExternal(false), + mHasMic(false), + mDropUntilNextSync(false) {} + +InputDevice::~InputDevice() { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + delete mMappers[i]; + } + mMappers.clear(); +} + +bool InputDevice::isEnabled() { + return getEventHub()->isDeviceEnabled(mId); +} + +void InputDevice::setEnabled(bool enabled, nsecs_t when) { + if (isEnabled() == enabled) { + return; + } + + if (enabled) { + getEventHub()->enableDevice(mId); + reset(when); + } else { + reset(when); + getEventHub()->disableDevice(mId); + } + // Must change generation to flag this device as changed + bumpGeneration(); +} + +void InputDevice::dump(std::string& dump) { + InputDeviceInfo deviceInfo; + getDeviceInfo(&deviceInfo); + + dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(), + deviceInfo.getDisplayName().c_str()); + dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration); + dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); + dump += StringPrintf(INDENT2 "AssociatedDisplayPort: "); + if (mAssociatedDisplayPort) { + dump += StringPrintf("%" PRIu8 "\n", *mAssociatedDisplayPort); + } else { + dump += "<none>\n"; + } + dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic)); + dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); + dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); + + const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); + if (!ranges.empty()) { + dump += INDENT2 "Motion Ranges:\n"; + for (size_t i = 0; i < ranges.size(); i++) { + const InputDeviceInfo::MotionRange& range = ranges[i]; + const char* label = getAxisLabel(range.axis); + char name[32]; + if (label) { + strncpy(name, label, sizeof(name)); + name[sizeof(name) - 1] = '\0'; + } else { + snprintf(name, sizeof(name), "%d", range.axis); + } + dump += StringPrintf(INDENT3 + "%s: source=0x%08x, " + "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", + name, range.source, range.min, range.max, range.flat, range.fuzz, + range.resolution); + } + } + + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->dump(dump); + } +} + +void InputDevice::addMapper(InputMapper* mapper) { + mMappers.push_back(mapper); +} + +void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, + uint32_t changes) { + mSources = 0; + + if (!isIgnored()) { + if (!changes) { // first time only + mContext->getEventHub()->getConfiguration(mId, &mConfiguration); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { + if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { + sp<KeyCharacterMap> keyboardLayout = + mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); + if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { + bumpGeneration(); + } + } + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { + if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { + std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); + if (mAlias != alias) { + mAlias = alias; + bumpGeneration(); + } + } + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) { + ssize_t index = config->disabledDevices.indexOf(mId); + bool enabled = index < 0; + setEnabled(enabled, when); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + // In most situations, no port will be specified. + mAssociatedDisplayPort = std::nullopt; + // Find the display port that corresponds to the current input port. + const std::string& inputPort = mIdentifier.location; + if (!inputPort.empty()) { + const std::unordered_map<std::string, uint8_t>& ports = config->portAssociations; + const auto& displayPort = ports.find(inputPort); + if (displayPort != ports.end()) { + mAssociatedDisplayPort = std::make_optional(displayPort->second); + } + } + } + + for (InputMapper* mapper : mMappers) { + mapper->configure(when, config, changes); + mSources |= mapper->getSources(); + } + } +} + +void InputDevice::reset(nsecs_t when) { + for (InputMapper* mapper : mMappers) { + mapper->reset(when); + } + + mContext->updateGlobalMetaState(); + + notifyReset(when); +} + +void InputDevice::process(const RawEvent* rawEvents, size_t count) { + // Process all of the events in order for each mapper. + // We cannot simply ask each mapper to process them in bulk because mappers may + // have side-effects that must be interleaved. For example, joystick movement events and + // gamepad button presses are handled by different mappers but they should be dispatched + // in the order received. + for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) { +#if DEBUG_RAW_EVENTS + ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64, + rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when); +#endif + + if (mDropUntilNextSync) { + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + mDropUntilNextSync = false; +#if DEBUG_RAW_EVENTS + ALOGD("Recovered from input event buffer overrun."); +#endif + } else { +#if DEBUG_RAW_EVENTS + ALOGD("Dropped input event while waiting for next input sync."); +#endif + } + } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { + ALOGI("Detected input event buffer overrun for device %s.", getName().c_str()); + mDropUntilNextSync = true; + reset(rawEvent->when); + } else { + for (InputMapper* mapper : mMappers) { + mapper->process(rawEvent); + } + } + --count; + } +} + +void InputDevice::timeoutExpired(nsecs_t when) { + for (InputMapper* mapper : mMappers) { + mapper->timeoutExpired(when); + } +} + +void InputDevice::updateExternalStylusState(const StylusState& state) { + for (InputMapper* mapper : mMappers) { + mapper->updateExternalStylusState(state); + } +} + +void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { + outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal, + mHasMic); + for (InputMapper* mapper : mMappers) { + mapper->populateDeviceInfo(outDeviceInfo); + } +} + +int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + return getState(sourceMask, keyCode, &InputMapper::getKeyCodeState); +} + +int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + return getState(sourceMask, scanCode, &InputMapper::getScanCodeState); +} + +int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { + return getState(sourceMask, switchCode, &InputMapper::getSwitchState); +} + +int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { + int32_t result = AKEY_STATE_UNKNOWN; + for (InputMapper* mapper : mMappers) { + if (sourcesMatchMask(mapper->getSources(), sourceMask)) { + // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that + // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. + int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); + if (currentResult >= AKEY_STATE_DOWN) { + return currentResult; + } else if (currentResult == AKEY_STATE_UP) { + result = currentResult; + } + } + } + return result; +} + +bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + bool result = false; + for (InputMapper* mapper : mMappers) { + if (sourcesMatchMask(mapper->getSources(), sourceMask)) { + result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + } + } + return result; +} + +void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, + int32_t token) { + for (InputMapper* mapper : mMappers) { + mapper->vibrate(pattern, patternSize, repeat, token); + } +} + +void InputDevice::cancelVibrate(int32_t token) { + for (InputMapper* mapper : mMappers) { + mapper->cancelVibrate(token); + } +} + +void InputDevice::cancelTouch(nsecs_t when) { + for (InputMapper* mapper : mMappers) { + mapper->cancelTouch(when); + } +} + +int32_t InputDevice::getMetaState() { + int32_t result = 0; + for (InputMapper* mapper : mMappers) { + result |= mapper->getMetaState(); + } + return result; +} + +void InputDevice::updateMetaState(int32_t keyCode) { + for (InputMapper* mapper : mMappers) { + mapper->updateMetaState(keyCode); + } +} + +void InputDevice::fadePointer() { + for (InputMapper* mapper : mMappers) { + mapper->fadePointer(); + } +} + +void InputDevice::bumpGeneration() { + mGeneration = mContext->bumpGeneration(); +} + +void InputDevice::notifyReset(nsecs_t when) { + NotifyDeviceResetArgs args(mContext->getNextSequenceNum(), when, mId); + mContext->getListener()->notifyDeviceReset(&args); +} + +std::optional<int32_t> InputDevice::getAssociatedDisplay() { + for (InputMapper* mapper : mMappers) { + std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay(); + if (associatedDisplayId) { + return associatedDisplayId; + } + } + + return std::nullopt; +} + +} // namespace android diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp new file mode 100644 index 0000000000..27cbf192d3 --- /dev/null +++ b/services/inputflinger/reader/InputReader.cpp @@ -0,0 +1,767 @@ +/* + * Copyright (C) 2010 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 "Macros.h" + +#include "InputReader.h" + +#include "CursorInputMapper.h" +#include "ExternalStylusInputMapper.h" +#include "InputReaderContext.h" +#include "JoystickInputMapper.h" +#include "KeyboardInputMapper.h" +#include "MultiTouchInputMapper.h" +#include "RotaryEncoderInputMapper.h" +#include "SingleTouchInputMapper.h" +#include "SwitchInputMapper.h" +#include "VibratorInputMapper.h" + +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <math.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> + +#include <log/log.h> + +#include <android-base/stringprintf.h> +#include <input/Keyboard.h> +#include <input/VirtualKeyMap.h> + + +using android::base::StringPrintf; + +namespace android { + +InputReader::InputReader(const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& policy, + const sp<InputListenerInterface>& listener) + : mContext(this), + mEventHub(eventHub), + mPolicy(policy), + mNextSequenceNum(1), + mGlobalMetaState(0), + mGeneration(1), + mDisableVirtualKeysTimeout(LLONG_MIN), + mNextTimeout(LLONG_MAX), + mConfigurationChangesToRefresh(0) { + mQueuedListener = new QueuedInputListener(listener); + + { // acquire lock + AutoMutex _l(mLock); + + refreshConfigurationLocked(0); + updateGlobalMetaStateLocked(); + } // release lock +} + +InputReader::~InputReader() { + for (size_t i = 0; i < mDevices.size(); i++) { + delete mDevices.valueAt(i); + } +} + +void InputReader::loopOnce() { + int32_t oldGeneration; + int32_t timeoutMillis; + bool inputDevicesChanged = false; + std::vector<InputDeviceInfo> inputDevices; + { // acquire lock + AutoMutex _l(mLock); + + oldGeneration = mGeneration; + timeoutMillis = -1; + + uint32_t changes = mConfigurationChangesToRefresh; + if (changes) { + mConfigurationChangesToRefresh = 0; + timeoutMillis = 0; + refreshConfigurationLocked(changes); + } else if (mNextTimeout != LLONG_MAX) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); + } + } // release lock + + size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); + + { // acquire lock + AutoMutex _l(mLock); + mReaderIsAliveCondition.broadcast(); + + if (count) { + processEventsLocked(mEventBuffer, count); + } + + if (mNextTimeout != LLONG_MAX) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + if (now >= mNextTimeout) { +#if DEBUG_RAW_EVENTS + ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); +#endif + mNextTimeout = LLONG_MAX; + timeoutExpiredLocked(now); + } + } + + if (oldGeneration != mGeneration) { + inputDevicesChanged = true; + getInputDevicesLocked(inputDevices); + } + } // release lock + + // Send out a message that the describes the changed input devices. + if (inputDevicesChanged) { + mPolicy->notifyInputDevicesChanged(inputDevices); + } + + // Flush queued events out to the listener. + // This must happen outside of the lock because the listener could potentially call + // back into the InputReader's methods, such as getScanCodeState, or become blocked + // on another thread similarly waiting to acquire the InputReader lock thereby + // resulting in a deadlock. This situation is actually quite plausible because the + // listener is actually the input dispatcher, which calls into the window manager, + // which occasionally calls into the input reader. + mQueuedListener->flush(); +} + +void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { + for (const RawEvent* rawEvent = rawEvents; count;) { + int32_t type = rawEvent->type; + size_t batchSize = 1; + if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { + int32_t deviceId = rawEvent->deviceId; + while (batchSize < count) { + if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || + rawEvent[batchSize].deviceId != deviceId) { + break; + } + batchSize += 1; + } +#if DEBUG_RAW_EVENTS + ALOGD("BatchSize: %zu Count: %zu", batchSize, count); +#endif + processEventsForDeviceLocked(deviceId, rawEvent, batchSize); + } else { + switch (rawEvent->type) { + case EventHubInterface::DEVICE_ADDED: + addDeviceLocked(rawEvent->when, rawEvent->deviceId); + break; + case EventHubInterface::DEVICE_REMOVED: + removeDeviceLocked(rawEvent->when, rawEvent->deviceId); + break; + case EventHubInterface::FINISHED_DEVICE_SCAN: + handleConfigurationChangedLocked(rawEvent->when); + break; + default: + ALOG_ASSERT(false); // can't happen + break; + } + } + count -= batchSize; + rawEvent += batchSize; + } +} + +void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); + return; + } + + InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); + uint32_t classes = mEventHub->getDeviceClasses(deviceId); + int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId); + + InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes); + device->configure(when, &mConfig, 0); + device->reset(when); + + if (device->isIgnored()) { + ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, + identifier.name.c_str()); + } else { + ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, identifier.name.c_str(), + device->getSources()); + } + + mDevices.add(deviceId, device); + bumpGenerationLocked(); + + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } +} + +void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { + InputDevice* device = nullptr; + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex < 0) { + ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); + return; + } + + device = mDevices.valueAt(deviceIndex); + mDevices.removeItemsAt(deviceIndex, 1); + bumpGenerationLocked(); + + if (device->isIgnored()) { + ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), + device->getName().c_str()); + } else { + ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(), + device->getName().c_str(), device->getSources()); + } + + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } + + device->reset(when); + delete device; +} + +InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber, + const InputDeviceIdentifier& identifier, + uint32_t classes) { + InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), + controllerNumber, identifier, classes); + + // External devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { + device->setExternal(true); + } + + // Devices with mics. + if (classes & INPUT_DEVICE_CLASS_MIC) { + device->setMic(true); + } + + // Switch-like devices. + if (classes & INPUT_DEVICE_CLASS_SWITCH) { + device->addMapper(new SwitchInputMapper(device)); + } + + // Scroll wheel-like devices. + if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) { + device->addMapper(new RotaryEncoderInputMapper(device)); + } + + // Vibrator-like devices. + if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { + device->addMapper(new VibratorInputMapper(device)); + } + + // Keyboard-like devices. + uint32_t keyboardSource = 0; + int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; + if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { + keyboardSource |= AINPUT_SOURCE_KEYBOARD; + } + if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { + keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; + } + if (classes & INPUT_DEVICE_CLASS_DPAD) { + keyboardSource |= AINPUT_SOURCE_DPAD; + } + if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { + keyboardSource |= AINPUT_SOURCE_GAMEPAD; + } + + if (keyboardSource != 0) { + device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); + } + + // Cursor-like devices. + if (classes & INPUT_DEVICE_CLASS_CURSOR) { + device->addMapper(new CursorInputMapper(device)); + } + + // Touchscreens and touchpad devices. + if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { + device->addMapper(new MultiTouchInputMapper(device)); + } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { + device->addMapper(new SingleTouchInputMapper(device)); + } + + // Joystick-like devices. + if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { + device->addMapper(new JoystickInputMapper(device)); + } + + // External stylus-like devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + device->addMapper(new ExternalStylusInputMapper(device)); + } + + return device; +} + +void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, + size_t count) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex < 0) { + ALOGW("Discarding event for unknown deviceId %d.", deviceId); + return; + } + + InputDevice* device = mDevices.valueAt(deviceIndex); + if (device->isIgnored()) { + // ALOGD("Discarding event for ignored deviceId %d.", deviceId); + return; + } + + device->process(rawEvents, count); +} + +void InputReader::timeoutExpiredLocked(nsecs_t when) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (!device->isIgnored()) { + device->timeoutExpired(when); + } + } +} + +void InputReader::handleConfigurationChangedLocked(nsecs_t when) { + // Reset global meta state because it depends on the list of all configured devices. + updateGlobalMetaStateLocked(); + + // Enqueue configuration changed. + NotifyConfigurationChangedArgs args(mContext.getNextSequenceNum(), when); + mQueuedListener->notifyConfigurationChanged(&args); +} + +void InputReader::refreshConfigurationLocked(uint32_t changes) { + mPolicy->getReaderConfiguration(&mConfig); + mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); + + if (changes) { + ALOGI("Reconfiguring input devices. changes=0x%08x", changes); + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + + if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { + mEventHub->requestReopenDevices(); + } else { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->configure(now, &mConfig, changes); + } + } + } +} + +void InputReader::updateGlobalMetaStateLocked() { + mGlobalMetaState = 0; + + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + mGlobalMetaState |= device->getMetaState(); + } +} + +int32_t InputReader::getGlobalMetaStateLocked() { + return mGlobalMetaState; +} + +void InputReader::notifyExternalStylusPresenceChanged() { + refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); +} + +void InputReader::getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { + InputDeviceInfo info; + device->getDeviceInfo(&info); + outDevices.push_back(info); + } + } +} + +void InputReader::dispatchExternalStylusState(const StylusState& state) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->updateExternalStylusState(state); + } +} + +void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { + mDisableVirtualKeysTimeout = time; +} + +bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, + int32_t scanCode) { + if (now < mDisableVirtualKeysTimeout) { + ALOGI("Dropping virtual key from device %s because virtual keys are " + "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", + device->getName().c_str(), (mDisableVirtualKeysTimeout - now) * 0.000001, keyCode, + scanCode); + return true; + } else { + return false; + } +} + +void InputReader::fadePointerLocked() { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->fadePointer(); + } +} + +void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { + if (when < mNextTimeout) { + mNextTimeout = when; + mEventHub->wake(); + } +} + +int32_t InputReader::bumpGenerationLocked() { + return ++mGeneration; +} + +void InputReader::getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) { + AutoMutex _l(mLock); + getInputDevicesLocked(outInputDevices); +} + +void InputReader::getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices) { + outInputDevices.clear(); + + size_t numDevices = mDevices.size(); + for (size_t i = 0; i < numDevices; i++) { + InputDevice* device = mDevices.valueAt(i); + if (!device->isIgnored()) { + InputDeviceInfo info; + device->getDeviceInfo(&info); + outInputDevices.push_back(info); + } + } +} + +int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) { + AutoMutex _l(mLock); + + return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); +} + +int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) { + AutoMutex _l(mLock); + + return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); +} + +int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { + AutoMutex _l(mLock); + + return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); +} + +int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, + GetStateFunc getStateFunc) { + int32_t result = AKEY_STATE_UNKNOWN; + if (deviceId >= 0) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + result = (device->*getStateFunc)(sourceMask, code); + } + } + } else { + size_t numDevices = mDevices.size(); + for (size_t i = 0; i < numDevices; i++) { + InputDevice* device = mDevices.valueAt(i); + if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that + // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. + int32_t currentResult = (device->*getStateFunc)(sourceMask, code); + if (currentResult >= AKEY_STATE_DOWN) { + return currentResult; + } else if (currentResult == AKEY_STATE_UP) { + result = currentResult; + } + } + } + } + return result; +} + +void InputReader::toggleCapsLockState(int32_t deviceId) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex < 0) { + ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId); + return; + } + + InputDevice* device = mDevices.valueAt(deviceIndex); + if (device->isIgnored()) { + return; + } + + device->updateMetaState(AKEYCODE_CAPS_LOCK); +} + +bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + AutoMutex _l(mLock); + + memset(outFlags, 0, numCodes); + return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); +} + +bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, + size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) { + bool result = false; + if (deviceId >= 0) { + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + } + } + } else { + size_t numDevices = mDevices.size(); + for (size_t i = 0; i < numDevices; i++) { + InputDevice* device = mDevices.valueAt(i); + if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { + result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + } + } + } + return result; +} + +void InputReader::requestRefreshConfiguration(uint32_t changes) { + AutoMutex _l(mLock); + + if (changes) { + bool needWake = !mConfigurationChangesToRefresh; + mConfigurationChangesToRefresh |= changes; + + if (needWake) { + mEventHub->wake(); + } + } +} + +void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, + ssize_t repeat, int32_t token) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + device->vibrate(pattern, patternSize, repeat, token); + } +} + +void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + device->cancelVibrate(token); + } +} + +bool InputReader::isInputDeviceEnabled(int32_t deviceId) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex >= 0) { + InputDevice* device = mDevices.valueAt(deviceIndex); + return device->isEnabled(); + } + ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); + return false; +} + +bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) { + AutoMutex _l(mLock); + + ssize_t deviceIndex = mDevices.indexOfKey(deviceId); + if (deviceIndex < 0) { + ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId); + return false; + } + + InputDevice* device = mDevices.valueAt(deviceIndex); + std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplay(); + // No associated display. By default, can dispatch to all displays. + if (!associatedDisplayId) { + return true; + } + + if (*associatedDisplayId == ADISPLAY_ID_NONE) { + ALOGW("Device has associated, but no associated display id."); + return true; + } + + return *associatedDisplayId == displayId; +} + +void InputReader::dump(std::string& dump) { + AutoMutex _l(mLock); + + mEventHub->dump(dump); + dump += "\n"; + + dump += "Input Reader State:\n"; + + for (size_t i = 0; i < mDevices.size(); i++) { + mDevices.valueAt(i)->dump(dump); + } + + dump += INDENT "Configuration:\n"; + dump += INDENT2 "ExcludedDeviceNames: ["; + for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { + if (i != 0) { + dump += ", "; + } + dump += mConfig.excludedDeviceNames[i]; + } + dump += "]\n"; + dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", + mConfig.virtualKeyQuietTime * 0.000001f); + + dump += StringPrintf(INDENT2 "PointerVelocityControlParameters: " + "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, " + "acceleration=%0.3f\n", + mConfig.pointerVelocityControlParameters.scale, + mConfig.pointerVelocityControlParameters.lowThreshold, + mConfig.pointerVelocityControlParameters.highThreshold, + mConfig.pointerVelocityControlParameters.acceleration); + + dump += StringPrintf(INDENT2 "WheelVelocityControlParameters: " + "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, " + "acceleration=%0.3f\n", + mConfig.wheelVelocityControlParameters.scale, + mConfig.wheelVelocityControlParameters.lowThreshold, + mConfig.wheelVelocityControlParameters.highThreshold, + mConfig.wheelVelocityControlParameters.acceleration); + + dump += StringPrintf(INDENT2 "PointerGesture:\n"); + dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(mConfig.pointerGesturesEnabled)); + dump += StringPrintf(INDENT3 "QuietInterval: %0.1fms\n", + mConfig.pointerGestureQuietInterval * 0.000001f); + dump += StringPrintf(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", + mConfig.pointerGestureDragMinSwitchSpeed); + dump += StringPrintf(INDENT3 "TapInterval: %0.1fms\n", + mConfig.pointerGestureTapInterval * 0.000001f); + dump += StringPrintf(INDENT3 "TapDragInterval: %0.1fms\n", + mConfig.pointerGestureTapDragInterval * 0.000001f); + dump += StringPrintf(INDENT3 "TapSlop: %0.1fpx\n", mConfig.pointerGestureTapSlop); + dump += StringPrintf(INDENT3 "MultitouchSettleInterval: %0.1fms\n", + mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); + dump += StringPrintf(INDENT3 "MultitouchMinDistance: %0.1fpx\n", + mConfig.pointerGestureMultitouchMinDistance); + dump += StringPrintf(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", + mConfig.pointerGestureSwipeTransitionAngleCosine); + dump += StringPrintf(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", + mConfig.pointerGestureSwipeMaxWidthRatio); + dump += StringPrintf(INDENT3 "MovementSpeedRatio: %0.1f\n", + mConfig.pointerGestureMovementSpeedRatio); + dump += StringPrintf(INDENT3 "ZoomSpeedRatio: %0.1f\n", mConfig.pointerGestureZoomSpeedRatio); + + dump += INDENT3 "Viewports:\n"; + mConfig.dump(dump); +} + +void InputReader::monitor() { + // Acquire and release the lock to ensure that the reader has not deadlocked. + mLock.lock(); + mEventHub->wake(); + mReaderIsAliveCondition.wait(mLock); + mLock.unlock(); + + // Check the EventHub + mEventHub->monitor(); +} + +// --- InputReader::ContextImpl --- + +InputReader::ContextImpl::ContextImpl(InputReader* reader) : mReader(reader) {} + +void InputReader::ContextImpl::updateGlobalMetaState() { + // lock is already held by the input loop + mReader->updateGlobalMetaStateLocked(); +} + +int32_t InputReader::ContextImpl::getGlobalMetaState() { + // lock is already held by the input loop + return mReader->getGlobalMetaStateLocked(); +} + +void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { + // lock is already held by the input loop + mReader->disableVirtualKeysUntilLocked(time); +} + +bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, InputDevice* device, + int32_t keyCode, int32_t scanCode) { + // lock is already held by the input loop + return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); +} + +void InputReader::ContextImpl::fadePointer() { + // lock is already held by the input loop + mReader->fadePointerLocked(); +} + +void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { + // lock is already held by the input loop + mReader->requestTimeoutAtTimeLocked(when); +} + +int32_t InputReader::ContextImpl::bumpGeneration() { + // lock is already held by the input loop + return mReader->bumpGenerationLocked(); +} + +void InputReader::ContextImpl::getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) { + // lock is already held by whatever called refreshConfigurationLocked + mReader->getExternalStylusDevicesLocked(outDevices); +} + +void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { + mReader->dispatchExternalStylusState(state); +} + +InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { + return mReader->mPolicy.get(); +} + +InputListenerInterface* InputReader::ContextImpl::getListener() { + return mReader->mQueuedListener.get(); +} + +EventHubInterface* InputReader::ContextImpl::getEventHub() { + return mReader->mEventHub.get(); +} + +uint32_t InputReader::ContextImpl::getNextSequenceNum() { + return (mReader->mNextSequenceNum)++; +} + +} // namespace android diff --git a/services/inputflinger/InputReaderFactory.cpp b/services/inputflinger/reader/InputReaderFactory.cpp index 3534f6b760..9f73680913 100644 --- a/services/inputflinger/InputReaderFactory.cpp +++ b/services/inputflinger/reader/InputReaderFactory.cpp @@ -15,13 +15,13 @@ */ #include "InputReaderFactory.h" + #include "InputReader.h" namespace android { -sp<InputReaderInterface> createInputReader( - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener) { +sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy, + const sp<InputListenerInterface>& listener) { return new InputReader(new EventHub(), policy, listener); } diff --git a/services/inputflinger/reader/Macros.h b/services/inputflinger/reader/Macros.h new file mode 100644 index 0000000000..827e31a1bd --- /dev/null +++ b/services/inputflinger/reader/Macros.h @@ -0,0 +1,84 @@ +/* + * 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_INPUTREADER_MACROS_H +#define _UI_INPUTREADER_MACROS_H + +#define LOG_TAG "InputReader" + +//#define LOG_NDEBUG 0 + +// Log debug messages for each raw event received from the EventHub. +#define DEBUG_RAW_EVENTS 0 + +// Log debug messages about touch screen filtering hacks. +#define DEBUG_HACKS 0 + +// Log debug messages about virtual key processing. +#define DEBUG_VIRTUAL_KEYS 0 + +// Log debug messages about pointers. +#define DEBUG_POINTERS 0 + +// Log debug messages about pointer assignment calculations. +#define DEBUG_POINTER_ASSIGNMENT 0 + +// Log debug messages about gesture detection. +#define DEBUG_GESTURES 0 + +// Log debug messages about the vibrator. +#define DEBUG_VIBRATOR 0 + +// Log debug messages about fusing stylus data. +#define DEBUG_STYLUS_FUSION 0 + +#define INDENT " " +#define INDENT2 " " +#define INDENT3 " " +#define INDENT4 " " +#define INDENT5 " " + +#include <input/Input.h> + +namespace android { + +// --- Static Functions --- + +template <typename T> +inline static T abs(const T& value) { + return value < 0 ? -value : value; +} + +template <typename T> +inline static T min(const T& a, const T& b) { + return a < b ? a : b; +} + +inline static float avg(float x, float y) { + return (x + y) / 2; +} + +static inline const char* toString(bool value) { + return value ? "true" : "false"; +} + +static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { + return (sources & sourceMask & ~AINPUT_SOURCE_CLASS_MASK) != 0; +} + +} // namespace android + +#endif // _UI_INPUTREADER_MACROS_H
\ No newline at end of file diff --git a/services/inputflinger/TouchVideoDevice.cpp b/services/inputflinger/reader/TouchVideoDevice.cpp index 19c1313dcd..c075078528 100644 --- a/services/inputflinger/TouchVideoDevice.cpp +++ b/services/inputflinger/reader/TouchVideoDevice.cpp @@ -37,10 +37,13 @@ using android::base::unique_fd; namespace android { TouchVideoDevice::TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath, - uint32_t height, uint32_t width, - const std::array<const int16_t*, NUM_BUFFERS>& readLocations) : - mFd(fd), mName(std::move(name)), mPath(std::move(devicePath)), - mHeight(height), mWidth(width), + uint32_t height, uint32_t width, + const std::array<const int16_t*, NUM_BUFFERS>& readLocations) + : mFd(fd), + mName(std::move(name)), + mPath(std::move(devicePath)), + mHeight(height), + mWidth(width), mReadLocations(readLocations) { mFrames.reserve(MAX_QUEUE_SIZE); }; @@ -60,11 +63,11 @@ std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePat } if (!(cap.capabilities & V4L2_CAP_TOUCH)) { ALOGE("Capability V4L2_CAP_TOUCH is not present, can't use device for heatmap data. " - "Make sure device specifies V4L2_CAP_TOUCH"); + "Make sure device specifies V4L2_CAP_TOUCH"); return nullptr; } - ALOGI("Opening video device: driver = %s, card = %s, bus_info = %s, version = %i", - cap.driver, cap.card, cap.bus_info, cap.version); + ALOGI("Opening video device: driver = %s, card = %s, bus_info = %s, version = %i", cap.driver, + cap.card, cap.bus_info, cap.version); std::string name = reinterpret_cast<const char*>(cap.card); struct v4l2_input v4l2_input_struct; @@ -77,7 +80,7 @@ std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePat if (v4l2_input_struct.type != V4L2_INPUT_TYPE_TOUCH) { ALOGE("Video device does not provide touch data. " - "Make sure device specifies V4L2_INPUT_TYPE_TOUCH."); + "Make sure device specifies V4L2_INPUT_TYPE_TOUCH."); return nullptr; } @@ -120,14 +123,14 @@ std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePat return nullptr; } if (buf.length != height * width * sizeof(int16_t)) { - ALOGE("Unexpected value of buf.length = %i (offset = %" PRIu32 ")", - buf.length, buf.m.offset); + ALOGE("Unexpected value of buf.length = %i (offset = %" PRIu32 ")", buf.length, + buf.m.offset); return nullptr; } - readLocations[i] = static_cast<const int16_t*>(mmap(nullptr /* start anywhere */, - buf.length, PROT_READ /* required */, MAP_SHARED /* recommended */, - fd.get(), buf.m.offset)); + readLocations[i] = static_cast<const int16_t*>( + mmap(nullptr /* start anywhere */, buf.length, PROT_READ /* required */, + MAP_SHARED /* recommended */, fd.get(), buf.m.offset)); if (readLocations[i] == MAP_FAILED) { ALOGE("%s: map failed: %s", __func__, strerror(errno)); return nullptr; @@ -150,8 +153,9 @@ std::unique_ptr<TouchVideoDevice> TouchVideoDevice::create(std::string devicePat } } // Using 'new' to access a non-public constructor. - return std::unique_ptr<TouchVideoDevice>(new TouchVideoDevice( - fd.release(), std::move(name), std::move(devicePath), height, width, readLocations)); + return std::unique_ptr<TouchVideoDevice>(new TouchVideoDevice(fd.release(), std::move(name), + std::move(devicePath), height, + width, readLocations)); } size_t TouchVideoDevice::readAndQueueFrames() { @@ -163,10 +167,10 @@ size_t TouchVideoDevice::readAndQueueFrames() { } // Concatenate the vectors, then clip up to maximum size allowed mFrames.insert(mFrames.end(), std::make_move_iterator(frames.begin()), - std::make_move_iterator(frames.end())); + std::make_move_iterator(frames.end())); if (mFrames.size() > MAX_QUEUE_SIZE) { ALOGE("More than %zu frames have been accumulated. Dropping %zu frames", MAX_QUEUE_SIZE, - mFrames.size() - MAX_QUEUE_SIZE); + mFrames.size() - MAX_QUEUE_SIZE); mFrames.erase(mFrames.begin(), mFrames.end() - MAX_QUEUE_SIZE); } return numFrames; @@ -193,8 +197,8 @@ std::optional<TouchVideoFrame> TouchVideoDevice::readFrame() { if ((buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) { // We use CLOCK_MONOTONIC for input events, so if the clocks don't match, // we can't compare timestamps. Just log a warning, since this is a driver issue - ALOGW("The timestamp %ld.%ld was not acquired using CLOCK_MONOTONIC", - buf.timestamp.tv_sec, buf.timestamp.tv_usec); + ALOGW("The timestamp %ld.%ld was not acquired using CLOCK_MONOTONIC", buf.timestamp.tv_sec, + buf.timestamp.tv_usec); } std::vector<int16_t> data(mHeight * mWidth); const int16_t* readFrom = mReadLocations[buf.index]; @@ -233,7 +237,7 @@ TouchVideoDevice::~TouchVideoDevice() { } for (const int16_t* buffer : mReadLocations) { void* bufferAddress = static_cast<void*>(const_cast<int16_t*>(buffer)); - result = munmap(bufferAddress, mHeight * mWidth * sizeof(int16_t)); + result = munmap(bufferAddress, mHeight * mWidth * sizeof(int16_t)); if (result == -1) { ALOGE("%s: Couldn't unmap: [%s]", __func__, strerror(errno)); } @@ -242,9 +246,9 @@ TouchVideoDevice::~TouchVideoDevice() { std::string TouchVideoDevice::dump() const { return StringPrintf("Video device %s (%s) : height=%" PRIu32 ", width=%" PRIu32 - ", fd=%i, hasValidFd=%s", - mName.c_str(), mPath.c_str(), mHeight, mWidth, mFd.get(), - hasValidFd() ? "true" : "false"); + ", fd=%i, hasValidFd=%s", + mName.c_str(), mPath.c_str(), mHeight, mWidth, mFd.get(), + hasValidFd() ? "true" : "false"); } } // namespace android diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 63a20ef3e2..794396acca 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -14,7 +14,6 @@ * limitations under the License. */ -// #ifndef _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H @@ -22,17 +21,17 @@ #include <input/Input.h> #include <input/InputDevice.h> -#include <input/Keyboard.h> -#include <input/KeyLayoutMap.h> #include <input/KeyCharacterMap.h> +#include <input/KeyLayoutMap.h> +#include <input/Keyboard.h> #include <input/VirtualKeyMap.h> -#include <utils/Mutex.h> -#include <utils/Log.h> -#include <utils/List.h> +#include <utils/BitSet.h> #include <utils/Errors.h> -#include <utils/PropertyMap.h> #include <utils/KeyedVector.h> -#include <utils/BitSet.h> +#include <utils/List.h> +#include <utils/Log.h> +#include <utils/Mutex.h> +#include <utils/PropertyMap.h> #include <linux/input.h> #include <sys/epoll.h> @@ -41,8 +40,8 @@ /* Convenience constants. */ -#define BTN_FIRST 0x100 // first button code -#define BTN_LAST 0x15f // last button code +#define BTN_FIRST 0x100 // first button code +#define BTN_LAST 0x15f // last button code namespace android { @@ -61,10 +60,10 @@ struct RawEvent { struct RawAbsoluteAxisInfo { bool valid; // true if the information is valid, false otherwise - int32_t minValue; // minimum value - int32_t maxValue; // maximum value - int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 - int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise + int32_t minValue; // minimum value + int32_t maxValue; // maximum value + int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 + int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise int32_t resolution; // resolution in units per mm or radians per mm inline void clear() { @@ -82,37 +81,37 @@ struct RawAbsoluteAxisInfo { */ enum { /* The input device is a keyboard or has buttons. */ - INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, + INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, /* The input device is an alpha-numeric keyboard (not just a dial pad). */ - INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, + INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ - INPUT_DEVICE_CLASS_TOUCH = 0x00000004, + INPUT_DEVICE_CLASS_TOUCH = 0x00000004, /* The input device is a cursor device such as a trackball or mouse. */ - INPUT_DEVICE_CLASS_CURSOR = 0x00000008, + INPUT_DEVICE_CLASS_CURSOR = 0x00000008, /* The input device is a multi-touch touchscreen. */ - INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, + INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, /* The input device is a directional pad (implies keyboard, has DPAD keys). */ - INPUT_DEVICE_CLASS_DPAD = 0x00000020, + INPUT_DEVICE_CLASS_DPAD = 0x00000020, /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ - INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, + INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, /* The input device has switches. */ - INPUT_DEVICE_CLASS_SWITCH = 0x00000080, + INPUT_DEVICE_CLASS_SWITCH = 0x00000080, /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ - INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, + INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, /* The input device has a vibrator (supports FF_RUMBLE). */ - INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, + INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, /* The input device has a microphone. */ - INPUT_DEVICE_CLASS_MIC = 0x00000400, + INPUT_DEVICE_CLASS_MIC = 0x00000400, /* The input device is an external stylus (has data we want to fuse with touch data). */ INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800, @@ -121,10 +120,10 @@ enum { INPUT_DEVICE_CLASS_ROTARY_ENCODER = 0x00001000, /* The input device is virtual (not a real device, not part of UI configuration). */ - INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, + INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, /* The input device is external (not built-in). */ - INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, + INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, }; /* @@ -148,8 +147,8 @@ extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); */ class EventHubInterface : public virtual RefBase { protected: - EventHubInterface() { } - virtual ~EventHubInterface() { } + EventHubInterface() {} + virtual ~EventHubInterface() {} public: // Synthetic raw event type codes produced when devices are added or removed. @@ -174,18 +173,17 @@ public: virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0; virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const = 0; + RawAbsoluteAxisInfo* outAxisInfo) const = 0; virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; - virtual status_t mapKey(int32_t deviceId, - int32_t scanCode, int32_t usageCode, int32_t metaState, - int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const = 0; + virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, + int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, + uint32_t* outFlags) const = 0; - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const = 0; + virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const = 0; // Sets devices that are excluded from opening. // This can be used to ignore input devices for sensors. @@ -213,13 +211,13 @@ public: virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, - int32_t* outValue) const = 0; + int32_t* outValue) const = 0; /* * Examine key input devices for specific framework keycode support */ virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const = 0; + uint8_t* outFlags) const = 0; virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; @@ -227,8 +225,8 @@ public: virtual bool hasLed(int32_t deviceId, int32_t led) const = 0; virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0; - virtual void getVirtualKeyDefinitions(int32_t deviceId, - std::vector<VirtualKeyDefinition>& outVirtualKeys) const = 0; + virtual void getVirtualKeyDefinitions( + int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const = 0; virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0; virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0; @@ -259,8 +257,7 @@ public: virtual status_t disableDevice(int32_t deviceId) = 0; }; -class EventHub : public EventHubInterface -{ +class EventHub : public EventHubInterface { public: EventHub(); @@ -273,18 +270,17 @@ public: virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const; virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const; + RawAbsoluteAxisInfo* outAxisInfo) const; virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; virtual bool hasInputProperty(int32_t deviceId, int property) const; - virtual status_t mapKey(int32_t deviceId, - int32_t scanCode, int32_t usageCode, int32_t metaState, - int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const; + virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, + int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, + uint32_t* outFlags) const; - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const; + virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const; virtual void setExcludedDevices(const std::vector<std::string>& devices); @@ -293,8 +289,8 @@ public: virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const; + virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) const; virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId); @@ -304,7 +300,7 @@ public: virtual void setLedState(int32_t deviceId, int32_t led, bool on); virtual void getVirtualKeyDefinitions(int32_t deviceId, - std::vector<VirtualKeyDefinition>& outVirtualKeys) const; + std::vector<VirtualKeyDefinition>& outVirtualKeys) const; virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const; virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map); @@ -357,7 +353,7 @@ private: int32_t controllerNumber; Device(int fd, int32_t id, const std::string& path, - const InputDeviceIdentifier& identifier); + const InputDeviceIdentifier& identifier); ~Device(); void close(); @@ -382,7 +378,7 @@ private: void addDeviceLocked(Device* device); void assignDescriptorLocked(InputDeviceIdentifier& identifier); - void closeDeviceByPathLocked(const char *devicePath); + void closeDeviceByPathLocked(const char* devicePath); void closeVideoDeviceByPathLocked(const std::string& devicePath); void closeDeviceLocked(Device* device); void closeAllDevicesLocked(); @@ -399,7 +395,7 @@ private: status_t unregisterDeviceFromEpollLocked(Device* device); void unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& videoDevice); - status_t scanDirLocked(const char *dirname); + status_t scanDirLocked(const char* dirname); status_t scanVideoDirLocked(const std::string& dirname); void scanDevicesLocked(); status_t readNotifyLocked(); @@ -455,8 +451,8 @@ private: */ std::vector<std::unique_ptr<TouchVideoDevice>> mUnattachedVideoDevices; - Device *mOpeningDevices; - Device *mClosingDevices; + Device* mOpeningDevices; + Device* mClosingDevices; bool mNeedToSendFinishedDeviceScan; bool mNeedToReopenDevices; diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h new file mode 100644 index 0000000000..57f0b319c8 --- /dev/null +++ b/services/inputflinger/reader/include/InputDevice.h @@ -0,0 +1,142 @@ +/* + * 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_INPUTREADER_INPUT_DEVICE_H +#define _UI_INPUTREADER_INPUT_DEVICE_H + +#include "EventHub.h" +#include "InputReaderBase.h" +#include "InputReaderContext.h" + +#include <input/DisplayViewport.h> +#include <input/InputDevice.h> +#include <utils/PropertyMap.h> + +#include <stdint.h> +#include <optional> +#include <vector> + +namespace android { + +class InputMapper; + +/* Represents the state of a single input device. */ +class InputDevice { +public: + InputDevice(InputReaderContext* context, int32_t id, int32_t generation, + int32_t controllerNumber, const InputDeviceIdentifier& identifier, + uint32_t classes); + ~InputDevice(); + + inline InputReaderContext* getContext() { return mContext; } + inline int32_t getId() const { return mId; } + inline int32_t getControllerNumber() const { return mControllerNumber; } + inline int32_t getGeneration() const { return mGeneration; } + inline const std::string getName() const { return mIdentifier.name; } + inline const std::string getDescriptor() { return mIdentifier.descriptor; } + inline uint32_t getClasses() const { return mClasses; } + inline uint32_t getSources() const { return mSources; } + + inline bool isExternal() { return mIsExternal; } + inline void setExternal(bool external) { mIsExternal = external; } + inline std::optional<uint8_t> getAssociatedDisplayPort() const { + return mAssociatedDisplayPort; + } + + inline void setMic(bool hasMic) { mHasMic = hasMic; } + inline bool hasMic() const { return mHasMic; } + + inline bool isIgnored() { return mMappers.empty(); } + + bool isEnabled(); + void setEnabled(bool enabled, nsecs_t when); + + void dump(std::string& dump); + void addMapper(InputMapper* mapper); + void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + void reset(nsecs_t when); + void process(const RawEvent* rawEvents, size_t count); + void timeoutExpired(nsecs_t when); + void updateExternalStylusState(const StylusState& state); + + void getDeviceInfo(InputDeviceInfo* outDeviceInfo); + int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags); + void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); + void cancelVibrate(int32_t token); + void cancelTouch(nsecs_t when); + + int32_t getMetaState(); + void updateMetaState(int32_t keyCode); + + void fadePointer(); + + void bumpGeneration(); + + void notifyReset(nsecs_t when); + + inline const PropertyMap& getConfiguration() { return mConfiguration; } + inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } + + bool hasKey(int32_t code) { return getEventHub()->hasScanCode(mId, code); } + + bool hasAbsoluteAxis(int32_t code) { + RawAbsoluteAxisInfo info; + getEventHub()->getAbsoluteAxisInfo(mId, code, &info); + return info.valid; + } + + bool isKeyPressed(int32_t code) { + return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; + } + + int32_t getAbsoluteAxisValue(int32_t code) { + int32_t value; + getEventHub()->getAbsoluteAxisValue(mId, code, &value); + return value; + } + + std::optional<int32_t> getAssociatedDisplay(); + +private: + InputReaderContext* mContext; + int32_t mId; + int32_t mGeneration; + int32_t mControllerNumber; + InputDeviceIdentifier mIdentifier; + std::string mAlias; + uint32_t mClasses; + + std::vector<InputMapper*> mMappers; + + uint32_t mSources; + bool mIsExternal; + std::optional<uint8_t> mAssociatedDisplayPort; + bool mHasMic; + bool mDropUntilNextSync; + + typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); + int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); + + PropertyMap mConfiguration; +}; + +} // namespace android + +#endif //_UI_INPUTREADER_INPUT_DEVICE_H diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h new file mode 100644 index 0000000000..e29c8f219c --- /dev/null +++ b/services/inputflinger/reader/include/InputReader.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2010 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_INPUTREADER_INPUT_READER_H +#define _UI_INPUTREADER_INPUT_READER_H + +#include "EventHub.h" +#include "InputListener.h" +#include "InputReaderBase.h" +#include "InputReaderContext.h" + +#include <utils/BitSet.h> +#include <utils/Condition.h> +#include <utils/KeyedVector.h> +#include <utils/Mutex.h> +#include <utils/Timers.h> + +#include <vector> + +namespace android { + +class InputDevice; +class InputMapper; +struct StylusState; + +/* The input reader reads raw event data from the event hub and processes it into input events + * that it sends to the input listener. Some functions of the input reader, such as early + * event filtering in low power states, are controlled by a separate policy object. + * + * The InputReader owns a collection of InputMappers. Most of the work it does happens + * on the input reader thread but the InputReader can receive queries from other system + * components running on arbitrary threads. To keep things manageable, the InputReader + * uses a single Mutex to guard its state. The Mutex may be held while calling into the + * EventHub or the InputReaderPolicy but it is never held while calling into the + * InputListener. + */ +class InputReader : public InputReaderInterface { +public: + InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, + const sp<InputListenerInterface>& listener); + virtual ~InputReader(); + + virtual void dump(std::string& dump); + virtual void monitor(); + + virtual void loopOnce(); + + virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices); + + virtual bool isInputDeviceEnabled(int32_t deviceId); + + virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode); + virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode); + virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw); + + virtual void toggleCapsLockState(int32_t deviceId); + + virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + + virtual void requestRefreshConfiguration(uint32_t changes); + + virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, + ssize_t repeat, int32_t token); + virtual void cancelVibrate(int32_t deviceId, int32_t token); + + virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId); +protected: + // These members are protected so they can be instrumented by test cases. + virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber, + const InputDeviceIdentifier& identifier, + uint32_t classes); + + class ContextImpl : public InputReaderContext { + InputReader* mReader; + + public: + explicit ContextImpl(InputReader* reader); + + virtual void updateGlobalMetaState(); + virtual int32_t getGlobalMetaState(); + virtual void disableVirtualKeysUntil(nsecs_t time); + virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, + int32_t scanCode); + virtual void fadePointer(); + virtual void requestTimeoutAtTime(nsecs_t when); + virtual int32_t bumpGeneration(); + virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices); + virtual void dispatchExternalStylusState(const StylusState& outState); + virtual InputReaderPolicyInterface* getPolicy(); + virtual InputListenerInterface* getListener(); + virtual EventHubInterface* getEventHub(); + virtual uint32_t getNextSequenceNum(); + } mContext; + + friend class ContextImpl; + +private: + Mutex mLock; + + Condition mReaderIsAliveCondition; + + sp<EventHubInterface> mEventHub; + sp<InputReaderPolicyInterface> mPolicy; + sp<QueuedInputListener> mQueuedListener; + + InputReaderConfiguration mConfig; + + // used by InputReaderContext::getNextSequenceNum() as a counter for event sequence numbers + uint32_t mNextSequenceNum; + + // The event queue. + static const int EVENT_BUFFER_SIZE = 256; + RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; + + KeyedVector<int32_t, InputDevice*> mDevices; + + // low-level input event decoding and device management + void processEventsLocked(const RawEvent* rawEvents, size_t count); + + void addDeviceLocked(nsecs_t when, int32_t deviceId); + void removeDeviceLocked(nsecs_t when, int32_t deviceId); + void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); + void timeoutExpiredLocked(nsecs_t when); + + void handleConfigurationChangedLocked(nsecs_t when); + + int32_t mGlobalMetaState; + void updateGlobalMetaStateLocked(); + int32_t getGlobalMetaStateLocked(); + + void notifyExternalStylusPresenceChanged(); + void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices); + void dispatchExternalStylusState(const StylusState& state); + + void fadePointerLocked(); + + int32_t mGeneration; + int32_t bumpGenerationLocked(); + + void getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices); + + nsecs_t mDisableVirtualKeysTimeout; + void disableVirtualKeysUntilLocked(nsecs_t time); + bool shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, + int32_t scanCode); + + nsecs_t mNextTimeout; + void requestTimeoutAtTimeLocked(nsecs_t when); + + uint32_t mConfigurationChangesToRefresh; + void refreshConfigurationLocked(uint32_t changes); + + // state queries + typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); + int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, + GetStateFunc getStateFunc); + bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_INPUT_READER_H diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h new file mode 100644 index 0000000000..3472346d44 --- /dev/null +++ b/services/inputflinger/reader/include/InputReaderContext.h @@ -0,0 +1,65 @@ +/* + * 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_INPUTREADER_INPUT_READER_CONTEXT_H +#define _UI_INPUTREADER_INPUT_READER_CONTEXT_H + +#include <input/InputDevice.h> + +#include <vector> + +namespace android { + +class EventHubInterface; +class InputDevice; +class InputListenerInterface; +class InputMapper; +class InputReaderPolicyInterface; +struct StylusState; + +/* Internal interface used by individual input devices to access global input device state + * and parameters maintained by the input reader. + */ +class InputReaderContext { +public: + InputReaderContext() {} + virtual ~InputReaderContext() {} + + virtual void updateGlobalMetaState() = 0; + virtual int32_t getGlobalMetaState() = 0; + + virtual void disableVirtualKeysUntil(nsecs_t time) = 0; + virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, + int32_t scanCode) = 0; + + virtual void fadePointer() = 0; + + virtual void requestTimeoutAtTime(nsecs_t when) = 0; + virtual int32_t bumpGeneration() = 0; + + virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) = 0; + virtual void dispatchExternalStylusState(const StylusState& outState) = 0; + + virtual InputReaderPolicyInterface* getPolicy() = 0; + virtual InputListenerInterface* getListener() = 0; + virtual EventHubInterface* getEventHub() = 0; + + virtual uint32_t getNextSequenceNum() = 0; +}; + +} // namespace android + +#endif // _UI_INPUTREADER_INPUT_READER_CONTEXT_H diff --git a/services/inputflinger/reader/include/StylusState.h b/services/inputflinger/reader/include/StylusState.h new file mode 100644 index 0000000000..17f158c9e1 --- /dev/null +++ b/services/inputflinger/reader/include/StylusState.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_INPUTREADER_STYLUS_STATE_H +#define _UI_INPUTREADER_STYLUS_STATE_H + +#include <input/Input.h> + +#include <limits.h> + +namespace android { + +struct StylusState { + /* Time the stylus event was received. */ + nsecs_t when; + /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ + float pressure; + /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ + uint32_t buttons; + /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ + int32_t toolType; + + void copyFrom(const StylusState& other) { + when = other.when; + pressure = other.pressure; + buttons = other.buttons; + toolType = other.toolType; + } + + void clear() { + when = LLONG_MAX; + pressure = 0.f; + buttons = 0; + toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + } +}; + +} // namespace android + +#endif // _UI_INPUTREADER_STYLUS_STATE_H diff --git a/services/inputflinger/TouchVideoDevice.h b/services/inputflinger/reader/include/TouchVideoDevice.h index 0e7e2ef496..5a32443f29 100644 --- a/services/inputflinger/TouchVideoDevice.h +++ b/services/inputflinger/reader/include/TouchVideoDevice.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#ifndef _INPUTFLINGER_TOUCH_VIDEO_DEVICE_H -#define _INPUTFLINGER_TOUCH_VIDEO_DEVICE_H +#ifndef _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H +#define _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H -#include <array> #include <android-base/unique_fd.h> #include <input/TouchVideoFrame.h> -#include <optional> #include <stdint.h> +#include <array> +#include <optional> #include <string> #include <vector> @@ -109,9 +109,9 @@ private: * The constructor is private because opening a v4l2 device requires many checks. * To get a new TouchVideoDevice, use 'create' instead. */ - explicit TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath, - uint32_t height, uint32_t width, - const std::array<const int16_t*, NUM_BUFFERS>& readLocations); + explicit TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath, uint32_t height, + uint32_t width, + const std::array<const int16_t*, NUM_BUFFERS>& readLocations); /** * Read all currently available frames. */ @@ -121,5 +121,7 @@ private: */ std::optional<TouchVideoFrame> readFrame(); }; + } // namespace android -#endif //_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H + +#endif // _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp new file mode 100644 index 0000000000..da85fda0e9 --- /dev/null +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -0,0 +1,480 @@ +/* + * 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 "Macros.h" + +#include "CursorInputMapper.h" + +#include "CursorButtonAccumulator.h" +#include "CursorScrollAccumulator.h" +#include "TouchCursorInputMapperCommon.h" + +namespace android { + +// --- CursorMotionAccumulator --- + +CursorMotionAccumulator::CursorMotionAccumulator() { + clearRelativeAxes(); +} + +void CursorMotionAccumulator::reset(InputDevice* device) { + clearRelativeAxes(); +} + +void CursorMotionAccumulator::clearRelativeAxes() { + mRelX = 0; + mRelY = 0; +} + +void CursorMotionAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_REL) { + switch (rawEvent->code) { + case REL_X: + mRelX = rawEvent->value; + break; + case REL_Y: + mRelY = rawEvent->value; + break; + } + } +} + +void CursorMotionAccumulator::finishSync() { + clearRelativeAxes(); +} + +// --- CursorInputMapper --- + +CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) {} + +CursorInputMapper::~CursorInputMapper() {} + +uint32_t CursorInputMapper::getSources() { + return mSource; +} + +void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + if (mParameters.mode == Parameters::MODE_POINTER) { + float minX, minY, maxX, maxY; + if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { + info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f); + } + } else { + info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); + } + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); + + if (mCursorScrollAccumulator.haveRelativeVWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); + } + if (mCursorScrollAccumulator.haveRelativeHWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); + } +} + +void CursorInputMapper::dump(std::string& dump) { + dump += INDENT2 "Cursor Input Mapper:\n"; + dumpParameters(dump); + dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale); + dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale); + dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision); + dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision); + dump += StringPrintf(INDENT3 "HaveVWheel: %s\n", + toString(mCursorScrollAccumulator.haveRelativeVWheel())); + dump += StringPrintf(INDENT3 "HaveHWheel: %s\n", + toString(mCursorScrollAccumulator.haveRelativeHWheel())); + dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); + dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); + dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation); + dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState); + dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); + dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); +} + +void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, + uint32_t changes) { + InputMapper::configure(when, config, changes); + + if (!changes) { // first time only + mCursorScrollAccumulator.configure(getDevice()); + + // Configure basic parameters. + configureParameters(); + + // Configure device mode. + switch (mParameters.mode) { + case Parameters::MODE_POINTER_RELATIVE: + // Should not happen during first time configuration. + ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER"); + mParameters.mode = Parameters::MODE_POINTER; + [[fallthrough]]; + case Parameters::MODE_POINTER: + mSource = AINPUT_SOURCE_MOUSE; + mXPrecision = 1.0f; + mYPrecision = 1.0f; + mXScale = 1.0f; + mYScale = 1.0f; + mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + break; + case Parameters::MODE_NAVIGATION: + mSource = AINPUT_SOURCE_TRACKBALL; + mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; + mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; + mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; + mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; + break; + } + + mVWheelScale = 1.0f; + mHWheelScale = 1.0f; + } + + if ((!changes && config->pointerCapture) || + (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) { + if (config->pointerCapture) { + if (mParameters.mode == Parameters::MODE_POINTER) { + mParameters.mode = Parameters::MODE_POINTER_RELATIVE; + mSource = AINPUT_SOURCE_MOUSE_RELATIVE; + // Keep PointerController around in order to preserve the pointer position. + mPointerController->fade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } else { + ALOGE("Cannot request pointer capture, device is not in MODE_POINTER"); + } + } else { + if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) { + mParameters.mode = Parameters::MODE_POINTER; + mSource = AINPUT_SOURCE_MOUSE; + } else { + ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE"); + } + } + bumpGeneration(); + if (changes) { + getDevice()->notifyReset(when); + } + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { + mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); + mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); + mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + mOrientation = DISPLAY_ORIENTATION_0; + if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { + std::optional<DisplayViewport> internalViewport = + config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + if (internalViewport) { + mOrientation = internalViewport->orientation; + } + } + + // Update the PointerController if viewports changed. + if (mParameters.mode == Parameters::MODE_POINTER) { + getPolicy()->obtainPointerController(getDeviceId()); + } + bumpGeneration(); + } +} + +void CursorInputMapper::configureParameters() { + mParameters.mode = Parameters::MODE_POINTER; + String8 cursorModeString; + if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { + if (cursorModeString == "navigation") { + mParameters.mode = Parameters::MODE_NAVIGATION; + } else if (cursorModeString != "pointer" && cursorModeString != "default") { + ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); + } + } + + mParameters.orientationAware = false; + getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), + mParameters.orientationAware); + + mParameters.hasAssociatedDisplay = false; + if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { + mParameters.hasAssociatedDisplay = true; + } +} + +void CursorInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; + dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n", + toString(mParameters.hasAssociatedDisplay)); + + switch (mParameters.mode) { + case Parameters::MODE_POINTER: + dump += INDENT4 "Mode: pointer\n"; + break; + case Parameters::MODE_POINTER_RELATIVE: + dump += INDENT4 "Mode: relative pointer\n"; + break; + case Parameters::MODE_NAVIGATION: + dump += INDENT4 "Mode: navigation\n"; + break; + default: + ALOG_ASSERT(false); + } + + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); +} + +void CursorInputMapper::reset(nsecs_t when) { + mButtonState = 0; + mDownTime = 0; + + mPointerVelocityControl.reset(); + mWheelXVelocityControl.reset(); + mWheelYVelocityControl.reset(); + + mCursorButtonAccumulator.reset(getDevice()); + mCursorMotionAccumulator.reset(getDevice()); + mCursorScrollAccumulator.reset(getDevice()); + + InputMapper::reset(when); +} + +void CursorInputMapper::process(const RawEvent* rawEvent) { + mCursorButtonAccumulator.process(rawEvent); + mCursorMotionAccumulator.process(rawEvent); + mCursorScrollAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void CursorInputMapper::sync(nsecs_t when) { + int32_t lastButtonState = mButtonState; + int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); + mButtonState = currentButtonState; + + bool wasDown = isPointerDown(lastButtonState); + bool down = isPointerDown(currentButtonState); + bool downChanged; + if (!wasDown && down) { + mDownTime = when; + downChanged = true; + } else if (wasDown && !down) { + downChanged = true; + } else { + downChanged = false; + } + nsecs_t downTime = mDownTime; + bool buttonsChanged = currentButtonState != lastButtonState; + int32_t buttonsPressed = currentButtonState & ~lastButtonState; + int32_t buttonsReleased = lastButtonState & ~currentButtonState; + + float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; + float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; + bool moved = deltaX != 0 || deltaY != 0; + + // Rotate delta according to orientation if needed. + if (mParameters.orientationAware && mParameters.hasAssociatedDisplay && + (deltaX != 0.0f || deltaY != 0.0f)) { + rotateDelta(mOrientation, &deltaX, &deltaY); + } + + // Move the pointer. + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; + + PointerCoords pointerCoords; + pointerCoords.clear(); + + float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); + float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); + bool scrolled = vscroll != 0 || hscroll != 0; + + mWheelYVelocityControl.move(when, nullptr, &vscroll); + mWheelXVelocityControl.move(when, &hscroll, nullptr); + + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + int32_t displayId; + if (mSource == AINPUT_SOURCE_MOUSE) { + if (moved || scrolled || buttonsChanged) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + + if (moved) { + mPointerController->move(deltaX, deltaY); + } + + if (buttonsChanged) { + mPointerController->setButtonState(currentButtonState); + } + + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } + + float x, y; + mPointerController->getPosition(&x, &y); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); + displayId = mPointerController->getDisplayId(); + } else { + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); + displayId = ADISPLAY_ID_NONE; + } + + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); + + // Moving an external trackball or mouse should wake the device. + // We don't do this for internal cursor devices to prevent them from waking up + // the device in your pocket. + // TODO: Use the input device configuration to control this behavior more finely. + uint32_t policyFlags = 0; + if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { + policyFlags |= POLICY_FLAG_WAKE; + } + + // Synthesize key down from buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + displayId, policyFlags, lastButtonState, currentButtonState); + + // Send motion event. + if (downChanged || moved || scrolled || buttonsChanged) { + int32_t metaState = mContext->getGlobalMetaState(); + int32_t buttonState = lastButtonState; + int32_t motionEventAction; + if (downChanged) { + motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; + } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) { + motionEventAction = AMOTION_EVENT_ACTION_MOVE; + } else { + motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; + } + + if (buttonsReleased) { + BitSet32 released(buttonsReleased); + while (!released.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); + buttonState &= ~actionButton; + NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&releaseArgs); + } + } + + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, motionEventAction, 0, 0, metaState, + currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + + if (buttonsPressed) { + BitSet32 pressed(buttonsPressed); + while (!pressed.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); + buttonState |= actionButton; + NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&pressArgs); + } + } + + ALOG_ASSERT(buttonState == currentButtonState); + + // Send hover move after UP to tell the application that the mouse is hovering now. + if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) { + NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + 0, metaState, currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&hoverArgs); + } + + // Send scroll events. + if (scrolled) { + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); + + NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, + currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&scrollArgs); + } + } + + // Synthesize key up from buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + displayId, policyFlags, lastButtonState, currentButtonState); + + mCursorMotionAccumulator.finishSync(); + mCursorScrollAccumulator.finishSync(); +} + +int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { + return getEventHub()->getScanCodeState(getDeviceId(), scanCode); + } else { + return AKEY_STATE_UNKNOWN; + } +} + +void CursorInputMapper::fadePointer() { + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } +} + +std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() { + if (mParameters.hasAssociatedDisplay) { + if (mParameters.mode == Parameters::MODE_POINTER) { + return std::make_optional(mPointerController->getDisplayId()); + } else { + // If the device is orientationAware and not a mouse, + // it expects to dispatch events to any display + return std::make_optional(ADISPLAY_ID_NONE); + } + } + return std::nullopt; +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h new file mode 100644 index 0000000000..eb2ad54c80 --- /dev/null +++ b/services/inputflinger/reader/mapper/CursorInputMapper.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_INPUTREADER_CURSOR_INPUT_MAPPER_H +#define _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H + +#include "CursorButtonAccumulator.h" +#include "CursorScrollAccumulator.h" +#include "InputMapper.h" + +#include <PointerControllerInterface.h> +#include <input/VelocityControl.h> + +namespace android { + +class VelocityControl; +class PointerControllerInterface; + +class CursorButtonAccumulator; +class CursorScrollAccumulator; + +/* Keeps track of cursor movements. */ +class CursorMotionAccumulator { +public: + CursorMotionAccumulator(); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + void finishSync(); + + inline int32_t getRelativeX() const { return mRelX; } + inline int32_t getRelativeY() const { return mRelY; } + +private: + int32_t mRelX; + int32_t mRelY; + + void clearRelativeAxes(); +}; + +class CursorInputMapper : public InputMapper { +public: + explicit CursorInputMapper(InputDevice* device); + virtual ~CursorInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + + virtual void fadePointer(); + + virtual std::optional<int32_t> getAssociatedDisplay(); + +private: + // Amount that trackball needs to move in order to generate a key event. + static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; + + // Immutable configuration parameters. + struct Parameters { + enum Mode { + MODE_POINTER, + MODE_POINTER_RELATIVE, + MODE_NAVIGATION, + }; + + Mode mode; + bool hasAssociatedDisplay; + bool orientationAware; + } mParameters; + + CursorButtonAccumulator mCursorButtonAccumulator; + CursorMotionAccumulator mCursorMotionAccumulator; + CursorScrollAccumulator mCursorScrollAccumulator; + + int32_t mSource; + float mXScale; + float mYScale; + float mXPrecision; + float mYPrecision; + + float mVWheelScale; + float mHWheelScale; + + // Velocity controls for mouse pointer and wheel movements. + // The controls for X and Y wheel movements are separate to keep them decoupled. + VelocityControl mPointerVelocityControl; + VelocityControl mWheelXVelocityControl; + VelocityControl mWheelYVelocityControl; + + int32_t mOrientation; + + sp<PointerControllerInterface> mPointerController; + + int32_t mButtonState; + nsecs_t mDownTime; + + void configureParameters(); + void dumpParameters(std::string& dump); + + void sync(nsecs_t when); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp new file mode 100644 index 0000000000..9aa0770245 --- /dev/null +++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp @@ -0,0 +1,92 @@ +/* + * 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 "Macros.h" + +#include "ExternalStylusInputMapper.h" + +#include "SingleTouchMotionAccumulator.h" +#include "TouchButtonAccumulator.h" + +namespace android { + +ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : InputMapper(device) {} + +uint32_t ExternalStylusInputMapper::getSources() { + return AINPUT_SOURCE_STYLUS; +} + +void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f); +} + +void ExternalStylusInputMapper::dump(std::string& dump) { + dump += INDENT2 "External Stylus Input Mapper:\n"; + dump += INDENT3 "Raw Stylus Axes:\n"; + dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); + dump += INDENT3 "Stylus State:\n"; + dumpStylusState(dump, mStylusState); +} + +void ExternalStylusInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, + uint32_t changes) { + getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); + mTouchButtonAccumulator.configure(getDevice()); +} + +void ExternalStylusInputMapper::reset(nsecs_t when) { + InputDevice* device = getDevice(); + mSingleTouchMotionAccumulator.reset(device); + mTouchButtonAccumulator.reset(device); + InputMapper::reset(when); +} + +void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { + mSingleTouchMotionAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void ExternalStylusInputMapper::sync(nsecs_t when) { + mStylusState.clear(); + + mStylusState.when = when; + + mStylusState.toolType = mTouchButtonAccumulator.getToolType(); + if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + + int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); + if (mRawPressureAxis.valid) { + mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; + } else if (mTouchButtonAccumulator.isToolActive()) { + mStylusState.pressure = 1.0f; + } else { + mStylusState.pressure = 0.0f; + } + + mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); + + mContext->dispatchExternalStylusState(mStylusState); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h new file mode 100644 index 0000000000..9764fbb3c1 --- /dev/null +++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h @@ -0,0 +1,51 @@ +/* + * 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_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H +#define _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H + +#include "InputMapper.h" + +#include "SingleTouchMotionAccumulator.h" +#include "StylusState.h" +#include "TouchButtonAccumulator.h" + +namespace android { + +class ExternalStylusInputMapper : public InputMapper { +public: + explicit ExternalStylusInputMapper(InputDevice* device); + virtual ~ExternalStylusInputMapper() = default; + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + virtual void sync(nsecs_t when); + +private: + SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; + RawAbsoluteAxisInfo mRawPressureAxis; + TouchButtonAccumulator mTouchButtonAccumulator; + + StylusState mStylusState; +}; + +} // namespace android + +#endif // _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp new file mode 100644 index 0000000000..d941528d14 --- /dev/null +++ b/services/inputflinger/reader/mapper/InputMapper.cpp @@ -0,0 +1,101 @@ +/* + * 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 "Macros.h" + +#include "InputMapper.h" + +#include "InputDevice.h" + +namespace android { + +InputMapper::InputMapper(InputDevice* device) : mDevice(device), mContext(device->getContext()) {} + +InputMapper::~InputMapper() {} + +void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { + info->addSource(getSources()); +} + +void InputMapper::dump(std::string& dump) {} + +void InputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, + uint32_t changes) {} + +void InputMapper::reset(nsecs_t when) {} + +void InputMapper::timeoutExpired(nsecs_t when) {} + +int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + return AKEY_STATE_UNKNOWN; +} + +int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + return AKEY_STATE_UNKNOWN; +} + +int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { + return AKEY_STATE_UNKNOWN; +} + +bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + return false; +} + +void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, + int32_t token) {} + +void InputMapper::cancelVibrate(int32_t token) {} + +void InputMapper::cancelTouch(nsecs_t when) {} + +int32_t InputMapper::getMetaState() { + return 0; +} + +void InputMapper::updateMetaState(int32_t keyCode) {} + +void InputMapper::updateExternalStylusState(const StylusState& state) {} + +void InputMapper::fadePointer() {} + +status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { + return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); +} + +void InputMapper::bumpGeneration() { + mDevice->bumpGeneration(); +} + +void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump, const RawAbsoluteAxisInfo& axis, + const char* name) { + if (axis.valid) { + dump += StringPrintf(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", name, + axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); + } else { + dump += StringPrintf(INDENT4 "%s: unknown range\n", name); + } +} + +void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) { + dump += StringPrintf(INDENT4 "When: %" PRId64 "\n", state.when); + dump += StringPrintf(INDENT4 "Pressure: %f\n", state.pressure); + dump += StringPrintf(INDENT4 "Button State: 0x%08x\n", state.buttons); + dump += StringPrintf(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h new file mode 100644 index 0000000000..cfd207cc4d --- /dev/null +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -0,0 +1,92 @@ +/* + * 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_INPUTREADER_INPUT_MAPPER_H +#define _UI_INPUTREADER_INPUT_MAPPER_H + +#include "EventHub.h" +#include "InputDevice.h" +#include "InputListener.h" +#include "InputReaderContext.h" +#include "StylusState.h" + +namespace android { + +/* An input mapper transforms raw input events into cooked event data. + * A single input device can have multiple associated input mappers in order to interpret + * different classes of events. + * + * InputMapper lifecycle: + * - create + * - configure with 0 changes + * - reset + * - process, process, process (may occasionally reconfigure with non-zero changes or reset) + * - reset + * - destroy + */ +class InputMapper { +public: + explicit InputMapper(InputDevice* device); + virtual ~InputMapper(); + + inline InputDevice* getDevice() { return mDevice; } + inline int32_t getDeviceId() { return mDevice->getId(); } + inline const std::string getDeviceName() { return mDevice->getName(); } + inline InputReaderContext* getContext() { return mContext; } + inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } + inline InputListenerInterface* getListener() { return mContext->getListener(); } + inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } + + virtual uint32_t getSources() = 0; + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent) = 0; + virtual void timeoutExpired(nsecs_t when); + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); + virtual void cancelVibrate(int32_t token); + virtual void cancelTouch(nsecs_t when); + + virtual int32_t getMetaState(); + virtual void updateMetaState(int32_t keyCode); + + virtual void updateExternalStylusState(const StylusState& state); + + virtual void fadePointer(); + virtual std::optional<int32_t> getAssociatedDisplay() { return std::nullopt; } + +protected: + InputDevice* mDevice; + InputReaderContext* mContext; + + status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); + void bumpGeneration(); + + static void dumpRawAbsoluteAxisInfo(std::string& dump, const RawAbsoluteAxisInfo& axis, + const char* name); + static void dumpStylusState(std::string& dump, const StylusState& state); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_INPUT_MAPPER_H diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp new file mode 100644 index 0000000000..b493e8368f --- /dev/null +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp @@ -0,0 +1,408 @@ +/* + * 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 "Macros.h" + +#include "JoystickInputMapper.h" + +namespace android { + +JoystickInputMapper::JoystickInputMapper(InputDevice* device) : InputMapper(device) {} + +JoystickInputMapper::~JoystickInputMapper() {} + +uint32_t JoystickInputMapper::getSources() { + return AINPUT_SOURCE_JOYSTICK; +} + +void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + for (size_t i = 0; i < mAxes.size(); i++) { + const Axis& axis = mAxes.valueAt(i); + addMotionRange(axis.axisInfo.axis, axis, info); + + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + addMotionRange(axis.axisInfo.highAxis, axis, info); + } + } +} + +void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info) { + info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz, + axis.resolution); + /* In order to ease the transition for developers from using the old axes + * to the newer, more semantically correct axes, we'll continue to register + * the old axes as duplicates of their corresponding new ones. */ + int32_t compatAxis = getCompatAxis(axisId); + if (compatAxis >= 0) { + info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, + axis.fuzz, axis.resolution); + } +} + +/* A mapping from axes the joystick actually has to the axes that should be + * artificially created for compatibility purposes. + * Returns -1 if no compatibility axis is needed. */ +int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { + switch (axis) { + case AMOTION_EVENT_AXIS_LTRIGGER: + return AMOTION_EVENT_AXIS_BRAKE; + case AMOTION_EVENT_AXIS_RTRIGGER: + return AMOTION_EVENT_AXIS_GAS; + } + return -1; +} + +void JoystickInputMapper::dump(std::string& dump) { + dump += INDENT2 "Joystick Input Mapper:\n"; + + dump += INDENT3 "Axes:\n"; + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + const Axis& axis = mAxes.valueAt(i); + const char* label = getAxisLabel(axis.axisInfo.axis); + if (label) { + dump += StringPrintf(INDENT4 "%s", label); + } else { + dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis); + } + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + label = getAxisLabel(axis.axisInfo.highAxis); + if (label) { + dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue); + } else { + dump += StringPrintf(" / %d (split at %d)", axis.axisInfo.highAxis, + axis.axisInfo.splitValue); + } + } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { + dump += " (invert)"; + } + + dump += StringPrintf(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", + axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); + dump += StringPrintf(INDENT4 " scale=%0.5f, offset=%0.5f, " + "highScale=%0.5f, highOffset=%0.5f\n", + axis.scale, axis.offset, axis.highScale, axis.highOffset); + dump += StringPrintf(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " + "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", + mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, + axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, + axis.rawAxisInfo.resolution); + } +} + +void JoystickInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, + uint32_t changes) { + InputMapper::configure(when, config, changes); + + if (!changes) { // first time only + // Collect all axes. + for (int32_t abs = 0; abs <= ABS_MAX; abs++) { + if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) & INPUT_DEVICE_CLASS_JOYSTICK)) { + continue; // axis must be claimed by a different device + } + + RawAbsoluteAxisInfo rawAxisInfo; + getAbsoluteAxisInfo(abs, &rawAxisInfo); + if (rawAxisInfo.valid) { + // Map axis. + AxisInfo axisInfo; + bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); + if (!explicitlyMapped) { + // Axis is not explicitly mapped, will choose a generic axis later. + axisInfo.mode = AxisInfo::MODE_NORMAL; + axisInfo.axis = -1; + } + + // Apply flat override. + int32_t rawFlat = + axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride; + + // Calculate scaling factors and limits. + Axis axis; + if (axisInfo.mode == AxisInfo::MODE_SPLIT) { + float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); + float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, highScale, + 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, + rawAxisInfo.resolution * scale); + } else if (isCenteredAxis(axisInfo.axis)) { + float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); + float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, scale, + offset, -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, + rawAxisInfo.resolution * scale); + } else { + float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, scale, + 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, + rawAxisInfo.resolution * scale); + } + + // To eliminate noise while the joystick is at rest, filter out small variations + // in axis values up front. + axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f; + + mAxes.add(abs, axis); + } + } + + // If there are too many axes, start dropping them. + // Prefer to keep explicitly mapped axes. + if (mAxes.size() > PointerCoords::MAX_AXES) { + ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.", + getDeviceName().c_str(), mAxes.size(), PointerCoords::MAX_AXES); + pruneAxes(true); + pruneAxes(false); + } + + // Assign generic axis ids to remaining axes. + int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + if (axis.axisInfo.axis < 0) { + while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 && + haveAxis(nextGenericAxisId)) { + nextGenericAxisId += 1; + } + + if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { + axis.axisInfo.axis = nextGenericAxisId; + nextGenericAxisId += 1; + } else { + ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " + "have already been assigned to other axes.", + getDeviceName().c_str(), mAxes.keyAt(i)); + mAxes.removeItemsAt(i--); + numAxes -= 1; + } + } + } + } +} + +bool JoystickInputMapper::haveAxis(int32_t axisId) { + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + const Axis& axis = mAxes.valueAt(i); + if (axis.axisInfo.axis == axisId || + (axis.axisInfo.mode == AxisInfo::MODE_SPLIT && axis.axisInfo.highAxis == axisId)) { + return true; + } + } + return false; +} + +void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { + size_t i = mAxes.size(); + while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { + if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { + continue; + } + ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", + getDeviceName().c_str(), mAxes.keyAt(i)); + mAxes.removeItemsAt(i); + } +} + +bool JoystickInputMapper::isCenteredAxis(int32_t axis) { + switch (axis) { + case AMOTION_EVENT_AXIS_X: + case AMOTION_EVENT_AXIS_Y: + case AMOTION_EVENT_AXIS_Z: + case AMOTION_EVENT_AXIS_RX: + case AMOTION_EVENT_AXIS_RY: + case AMOTION_EVENT_AXIS_RZ: + case AMOTION_EVENT_AXIS_HAT_X: + case AMOTION_EVENT_AXIS_HAT_Y: + case AMOTION_EVENT_AXIS_ORIENTATION: + case AMOTION_EVENT_AXIS_RUDDER: + case AMOTION_EVENT_AXIS_WHEEL: + return true; + default: + return false; + } +} + +void JoystickInputMapper::reset(nsecs_t when) { + // Recenter all axes. + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + axis.resetValue(); + } + + InputMapper::reset(when); +} + +void JoystickInputMapper::process(const RawEvent* rawEvent) { + switch (rawEvent->type) { + case EV_ABS: { + ssize_t index = mAxes.indexOfKey(rawEvent->code); + if (index >= 0) { + Axis& axis = mAxes.editValueAt(index); + float newValue, highNewValue; + switch (axis.axisInfo.mode) { + case AxisInfo::MODE_INVERT: + newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) * axis.scale + + axis.offset; + highNewValue = 0.0f; + break; + case AxisInfo::MODE_SPLIT: + if (rawEvent->value < axis.axisInfo.splitValue) { + newValue = (axis.axisInfo.splitValue - rawEvent->value) * axis.scale + + axis.offset; + highNewValue = 0.0f; + } else if (rawEvent->value > axis.axisInfo.splitValue) { + newValue = 0.0f; + highNewValue = + (rawEvent->value - axis.axisInfo.splitValue) * axis.highScale + + axis.highOffset; + } else { + newValue = 0.0f; + highNewValue = 0.0f; + } + break; + default: + newValue = rawEvent->value * axis.scale + axis.offset; + highNewValue = 0.0f; + break; + } + axis.newValue = newValue; + axis.highNewValue = highNewValue; + } + break; + } + + case EV_SYN: + switch (rawEvent->code) { + case SYN_REPORT: + sync(rawEvent->when, false /*force*/); + break; + } + break; + } +} + +void JoystickInputMapper::sync(nsecs_t when, bool force) { + if (!filterAxes(force)) { + return; + } + + int32_t metaState = mContext->getGlobalMetaState(); + int32_t buttonState = 0; + + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + + PointerCoords pointerCoords; + pointerCoords.clear(); + + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + const Axis& axis = mAxes.valueAt(i); + setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, + axis.highCurrentValue); + } + } + + // Moving a joystick axis should not wake the device because joysticks can + // be fairly noisy even when not in use. On the other hand, pushing a gamepad + // button will likely wake the device. + // TODO: Use the input device configuration to control this behavior more finely. + uint32_t policyFlags = 0; + + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), + AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, 0, + /* videoFrames */ {}); + getListener()->notifyMotion(&args); +} + +void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, + float value) { + pointerCoords->setAxisValue(axis, value); + /* In order to ease the transition for developers from using the old axes + * to the newer, more semantically correct axes, we'll continue to produce + * values for the old axes as mirrors of the value of their corresponding + * new axes. */ + int32_t compatAxis = getCompatAxis(axis); + if (compatAxis >= 0) { + pointerCoords->setAxisValue(compatAxis, value); + } +} + +bool JoystickInputMapper::filterAxes(bool force) { + bool atLeastOneSignificantChange = force; + size_t numAxes = mAxes.size(); + for (size_t i = 0; i < numAxes; i++) { + Axis& axis = mAxes.editValueAt(i); + if (force || + hasValueChangedSignificantly(axis.filter, axis.newValue, axis.currentValue, axis.min, + axis.max)) { + axis.currentValue = axis.newValue; + atLeastOneSignificantChange = true; + } + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + if (force || + hasValueChangedSignificantly(axis.filter, axis.highNewValue, axis.highCurrentValue, + axis.min, axis.max)) { + axis.highCurrentValue = axis.highNewValue; + atLeastOneSignificantChange = true; + } + } + } + return atLeastOneSignificantChange; +} + +bool JoystickInputMapper::hasValueChangedSignificantly(float filter, float newValue, + float currentValue, float min, float max) { + if (newValue != currentValue) { + // Filter out small changes in value unless the value is converging on the axis + // bounds or center point. This is intended to reduce the amount of information + // sent to applications by particularly noisy joysticks (such as PS3). + if (fabs(newValue - currentValue) > filter || + hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) || + hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) || + hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { + return true; + } + } + return false; +} + +bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(float filter, float newValue, + float currentValue, + float thresholdValue) { + float newDistance = fabs(newValue - thresholdValue); + if (newDistance < filter) { + float oldDistance = fabs(currentValue - thresholdValue); + if (newDistance < oldDistance) { + return true; + } + } + return false; +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h new file mode 100644 index 0000000000..1b071d0480 --- /dev/null +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h @@ -0,0 +1,111 @@ +/* + * 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_INPUTREADER_JOYSTICK_INPUT_MAPPER_H +#define _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H + +#include "InputMapper.h" + +namespace android { + +class JoystickInputMapper : public InputMapper { +public: + explicit JoystickInputMapper(InputDevice* device); + virtual ~JoystickInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + +private: + struct Axis { + RawAbsoluteAxisInfo rawAxisInfo; + AxisInfo axisInfo; + + bool explicitlyMapped; // true if the axis was explicitly assigned an axis id + + float scale; // scale factor from raw to normalized values + float offset; // offset to add after scaling for normalization + float highScale; // scale factor from raw to normalized values of high split + float highOffset; // offset to add after scaling for normalization of high split + + float min; // normalized inclusive minimum + float max; // normalized inclusive maximum + float flat; // normalized flat region size + float fuzz; // normalized error tolerance + float resolution; // normalized resolution in units/mm + + float filter; // filter out small variations of this size + float currentValue; // current value + float newValue; // most recent value + float highCurrentValue; // current value of high split + float highNewValue; // most recent value of high split + + void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, + bool explicitlyMapped, float scale, float offset, float highScale, + float highOffset, float min, float max, float flat, float fuzz, + float resolution) { + this->rawAxisInfo = rawAxisInfo; + this->axisInfo = axisInfo; + this->explicitlyMapped = explicitlyMapped; + this->scale = scale; + this->offset = offset; + this->highScale = highScale; + this->highOffset = highOffset; + this->min = min; + this->max = max; + this->flat = flat; + this->fuzz = fuzz; + this->resolution = resolution; + this->filter = 0; + resetValue(); + } + + void resetValue() { + this->currentValue = 0; + this->newValue = 0; + this->highCurrentValue = 0; + this->highNewValue = 0; + } + }; + + // Axes indexed by raw ABS_* axis index. + KeyedVector<int32_t, Axis> mAxes; + + void sync(nsecs_t when, bool force); + + bool haveAxis(int32_t axisId); + void pruneAxes(bool ignoreExplicitlyMappedAxes); + bool filterAxes(bool force); + + static bool hasValueChangedSignificantly(float filter, float newValue, float currentValue, + float min, float max); + static bool hasMovedNearerToValueWithinFilteredRange(float filter, float newValue, + float currentValue, float thresholdValue); + + static bool isCenteredAxis(int32_t axis); + static int32_t getCompatAxis(int32_t axis); + + static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info); + static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, float value); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp new file mode 100644 index 0000000000..0e91c0e2cc --- /dev/null +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -0,0 +1,412 @@ +/* + * 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 "Macros.h" + +#include "KeyboardInputMapper.h" + +namespace android { + +// --- Static Definitions --- + +static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, + const int32_t map[][4], size_t mapSize) { + if (orientation != DISPLAY_ORIENTATION_0) { + for (size_t i = 0; i < mapSize; i++) { + if (value == map[i][0]) { + return map[i][orientation]; + } + } + } + return value; +} + +static const int32_t keyCodeRotationMap[][4] = { + // key codes enumerated counter-clockwise with the original (unrotated) key first + // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation + {AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT}, + {AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN}, + {AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT}, + {AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP}, + {AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT, + AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT}, + {AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP, + AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN}, + {AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT, + AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT}, + {AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN, + AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP}, +}; + +static const size_t keyCodeRotationMapSize = + sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); + +static int32_t rotateStemKey(int32_t value, int32_t orientation, const int32_t map[][2], + size_t mapSize) { + if (orientation == DISPLAY_ORIENTATION_180) { + for (size_t i = 0; i < mapSize; i++) { + if (value == map[i][0]) { + return map[i][1]; + } + } + } + return value; +} + +// The mapping can be defined using input device configuration properties keyboard.rotated.stem_X +static int32_t stemKeyRotationMap[][2] = { + // key codes enumerated with the original (unrotated) key first + // no rotation, 180 degree rotation + {AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY}, + {AKEYCODE_STEM_1, AKEYCODE_STEM_1}, + {AKEYCODE_STEM_2, AKEYCODE_STEM_2}, + {AKEYCODE_STEM_3, AKEYCODE_STEM_3}, +}; + +static const size_t stemKeyRotationMapSize = + sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]); + +static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { + keyCode = rotateStemKey(keyCode, orientation, stemKeyRotationMap, stemKeyRotationMapSize); + return rotateValueUsingRotationMap(keyCode, orientation, keyCodeRotationMap, + keyCodeRotationMapSize); +} + +// --- KeyboardInputMapper --- + +KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType) + : InputMapper(device), mSource(source), mKeyboardType(keyboardType) {} + +KeyboardInputMapper::~KeyboardInputMapper() {} + +uint32_t KeyboardInputMapper::getSources() { + return mSource; +} + +int32_t KeyboardInputMapper::getOrientation() { + if (mViewport) { + return mViewport->orientation; + } + return DISPLAY_ORIENTATION_0; +} + +int32_t KeyboardInputMapper::getDisplayId() { + if (mViewport) { + return mViewport->displayId; + } + return ADISPLAY_ID_NONE; +} + +void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + info->setKeyboardType(mKeyboardType); + info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); +} + +void KeyboardInputMapper::dump(std::string& dump) { + dump += INDENT2 "Keyboard Input Mapper:\n"; + dumpParameters(dump); + dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType); + dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation()); + dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size()); + dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState); + dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); +} + +void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, + uint32_t changes) { + InputMapper::configure(when, config, changes); + + if (!changes) { // first time only + // Configure basic parameters. + configureParameters(); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + if (mParameters.orientationAware) { + mViewport = config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + } + } +} + +static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* property) { + int32_t mapped = 0; + if (config.tryGetProperty(String8(property), mapped) && mapped > 0) { + for (size_t i = 0; i < stemKeyRotationMapSize; i++) { + if (stemKeyRotationMap[i][0] == keyCode) { + stemKeyRotationMap[i][1] = mapped; + return; + } + } + } +} + +void KeyboardInputMapper::configureParameters() { + mParameters.orientationAware = false; + const PropertyMap& config = getDevice()->getConfiguration(); + config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware); + + if (mParameters.orientationAware) { + mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary"); + mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1"); + mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2"); + mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3"); + } + + mParameters.handlesKeyRepeat = false; + config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat); +} + +void KeyboardInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); + dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", toString(mParameters.handlesKeyRepeat)); +} + +void KeyboardInputMapper::reset(nsecs_t when) { + mMetaState = AMETA_NONE; + mDownTime = 0; + mKeyDowns.clear(); + mCurrentHidUsage = 0; + + resetLedState(); + + InputMapper::reset(when); +} + +void KeyboardInputMapper::process(const RawEvent* rawEvent) { + switch (rawEvent->type) { + case EV_KEY: { + int32_t scanCode = rawEvent->code; + int32_t usageCode = mCurrentHidUsage; + mCurrentHidUsage = 0; + + if (isKeyboardOrGamepadKey(scanCode)) { + processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode); + } + break; + } + case EV_MSC: { + if (rawEvent->code == MSC_SCAN) { + mCurrentHidUsage = rawEvent->value; + } + break; + } + case EV_SYN: { + if (rawEvent->code == SYN_REPORT) { + mCurrentHidUsage = 0; + } + } + } +} + +bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { + return scanCode < BTN_MOUSE || scanCode >= KEY_OK || + (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) || + (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); +} + +bool KeyboardInputMapper::isMediaKey(int32_t keyCode) { + switch (keyCode) { + case AKEYCODE_MEDIA_PLAY: + case AKEYCODE_MEDIA_PAUSE: + case AKEYCODE_MEDIA_PLAY_PAUSE: + case AKEYCODE_MUTE: + case AKEYCODE_HEADSETHOOK: + case AKEYCODE_MEDIA_STOP: + case AKEYCODE_MEDIA_NEXT: + case AKEYCODE_MEDIA_PREVIOUS: + case AKEYCODE_MEDIA_REWIND: + case AKEYCODE_MEDIA_RECORD: + case AKEYCODE_MEDIA_FAST_FORWARD: + case AKEYCODE_MEDIA_SKIP_FORWARD: + case AKEYCODE_MEDIA_SKIP_BACKWARD: + case AKEYCODE_MEDIA_STEP_FORWARD: + case AKEYCODE_MEDIA_STEP_BACKWARD: + case AKEYCODE_MEDIA_AUDIO_TRACK: + case AKEYCODE_VOLUME_UP: + case AKEYCODE_VOLUME_DOWN: + case AKEYCODE_VOLUME_MUTE: + case AKEYCODE_TV_AUDIO_DESCRIPTION: + case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP: + case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN: + return true; + } + return false; +} + +void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) { + int32_t keyCode; + int32_t keyMetaState; + uint32_t policyFlags; + + if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState, &keyCode, + &keyMetaState, &policyFlags)) { + keyCode = AKEYCODE_UNKNOWN; + keyMetaState = mMetaState; + policyFlags = 0; + } + + if (down) { + // Rotate key codes according to orientation if needed. + if (mParameters.orientationAware) { + keyCode = rotateKeyCode(keyCode, getOrientation()); + } + + // Add key down. + ssize_t keyDownIndex = findKeyDown(scanCode); + if (keyDownIndex >= 0) { + // key repeat, be sure to use same keycode as before in case of rotation + keyCode = mKeyDowns[keyDownIndex].keyCode; + } else { + // key down + if ((policyFlags & POLICY_FLAG_VIRTUAL) && + mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) { + return; + } + if (policyFlags & POLICY_FLAG_GESTURE) { + mDevice->cancelTouch(when); + } + + KeyDown keyDown; + keyDown.keyCode = keyCode; + keyDown.scanCode = scanCode; + mKeyDowns.push_back(keyDown); + } + + mDownTime = when; + } else { + // Remove key down. + ssize_t keyDownIndex = findKeyDown(scanCode); + if (keyDownIndex >= 0) { + // key up, be sure to use same keycode as before in case of rotation + keyCode = mKeyDowns[keyDownIndex].keyCode; + mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex); + } else { + // key was not actually down + ALOGI("Dropping key up from device %s because the key was not down. " + "keyCode=%d, scanCode=%d", + getDeviceName().c_str(), keyCode, scanCode); + return; + } + } + + if (updateMetaStateIfNeeded(keyCode, down)) { + // If global meta state changed send it along with the key. + // If it has not changed then we'll use what keymap gave us, + // since key replacement logic might temporarily reset a few + // meta bits for given key. + keyMetaState = mMetaState; + } + + nsecs_t downTime = mDownTime; + + // Key down on external an keyboard should wake the device. + // We don't do this for internal keyboards to prevent them from waking up in your pocket. + // For internal keyboards, the key layout file should specify the policy flags for + // each wake key individually. + // TODO: Use the input device configuration to control this behavior more finely. + if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) { + policyFlags |= POLICY_FLAG_WAKE; + } + + if (mParameters.handlesKeyRepeat) { + policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; + } + + NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, getDisplayId(), + policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime); + getListener()->notifyKey(&args); +} + +ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { + size_t n = mKeyDowns.size(); + for (size_t i = 0; i < n; i++) { + if (mKeyDowns[i].scanCode == scanCode) { + return i; + } + } + return -1; +} + +int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); +} + +int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + return getEventHub()->getScanCodeState(getDeviceId(), scanCode); +} + +bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); +} + +int32_t KeyboardInputMapper::getMetaState() { + return mMetaState; +} + +void KeyboardInputMapper::updateMetaState(int32_t keyCode) { + updateMetaStateIfNeeded(keyCode, false); +} + +bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) { + int32_t oldMetaState = mMetaState; + int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState); + bool metaStateChanged = oldMetaState != newMetaState; + if (metaStateChanged) { + mMetaState = newMetaState; + updateLedState(false); + + getContext()->updateGlobalMetaState(); + } + + return metaStateChanged; +} + +void KeyboardInputMapper::resetLedState() { + initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK); + initializeLedState(mNumLockLedState, ALED_NUM_LOCK); + initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK); + + updateLedState(true); +} + +void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { + ledState.avail = getEventHub()->hasLed(getDeviceId(), led); + ledState.on = false; +} + +void KeyboardInputMapper::updateLedState(bool reset) { + updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, AMETA_CAPS_LOCK_ON, reset); + updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, AMETA_NUM_LOCK_ON, reset); + updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, reset); +} + +void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t led, + int32_t modifier, bool reset) { + if (ledState.avail) { + bool desiredState = (mMetaState & modifier) != 0; + if (reset || ledState.on != desiredState) { + getEventHub()->setLedState(getDeviceId(), led, desiredState); + ledState.on = desiredState; + } + } +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h new file mode 100644 index 0000000000..7a68fc33f8 --- /dev/null +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -0,0 +1,99 @@ +/* + * 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_INPUTREADER_KEYBOARD_INPUT_MAPPER_H +#define _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H + +#include "InputMapper.h" + +namespace android { + +class KeyboardInputMapper : public InputMapper { +public: + KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); + virtual ~KeyboardInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + + virtual int32_t getMetaState(); + virtual void updateMetaState(int32_t keyCode); + +private: + // The current viewport. + std::optional<DisplayViewport> mViewport; + + struct KeyDown { + int32_t keyCode; + int32_t scanCode; + }; + + uint32_t mSource; + int32_t mKeyboardType; + + std::vector<KeyDown> mKeyDowns; // keys that are down + int32_t mMetaState; + nsecs_t mDownTime; // time of most recent key down + + int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none + + struct LedState { + bool avail; // led is available + bool on; // we think the led is currently on + }; + LedState mCapsLockLedState; + LedState mNumLockLedState; + LedState mScrollLockLedState; + + // Immutable configuration parameters. + struct Parameters { + bool orientationAware; + bool handlesKeyRepeat; + } mParameters; + + void configureParameters(); + void dumpParameters(std::string& dump); + + int32_t getOrientation(); + int32_t getDisplayId(); + + bool isKeyboardOrGamepadKey(int32_t scanCode); + bool isMediaKey(int32_t keyCode); + + void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode); + + bool updateMetaStateIfNeeded(int32_t keyCode, bool down); + + ssize_t findKeyDown(int32_t scanCode); + + void resetLedState(); + void initializeLedState(LedState& ledState, int32_t led); + void updateLedState(bool reset); + void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp new file mode 100644 index 0000000000..7460a3130e --- /dev/null +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -0,0 +1,361 @@ +/* + * 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 "Macros.h" + +#include "MultiTouchInputMapper.h" + +namespace android { + +// --- Constants --- + +// Maximum number of slots supported when using the slot-based Multitouch Protocol B. +static constexpr size_t MAX_SLOTS = 32; + +// --- MultiTouchMotionAccumulator --- + +MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() + : mCurrentSlot(-1), + mSlots(nullptr), + mSlotCount(0), + mUsingSlotsProtocol(false), + mHaveStylus(false) {} + +MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { + delete[] mSlots; +} + +void MultiTouchMotionAccumulator::configure(InputDevice* device, size_t slotCount, + bool usingSlotsProtocol) { + mSlotCount = slotCount; + mUsingSlotsProtocol = usingSlotsProtocol; + mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); + + delete[] mSlots; + mSlots = new Slot[slotCount]; +} + +void MultiTouchMotionAccumulator::reset(InputDevice* device) { + // Unfortunately there is no way to read the initial contents of the slots. + // So when we reset the accumulator, we must assume they are all zeroes. + if (mUsingSlotsProtocol) { + // Query the driver for the current slot index and use it as the initial slot + // before we start reading events from the device. It is possible that the + // current slot index will not be the same as it was when the first event was + // written into the evdev buffer, which means the input mapper could start + // out of sync with the initial state of the events in the evdev buffer. + // In the extremely unlikely case that this happens, the data from + // two slots will be confused until the next ABS_MT_SLOT event is received. + // This can cause the touch point to "jump", but at least there will be + // no stuck touches. + int32_t initialSlot; + status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), ABS_MT_SLOT, + &initialSlot); + if (status) { + ALOGD("Could not retrieve current multitouch slot index. status=%d", status); + initialSlot = -1; + } + clearSlots(initialSlot); + } else { + clearSlots(-1); + } + mDeviceTimestamp = 0; +} + +void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { + if (mSlots) { + for (size_t i = 0; i < mSlotCount; i++) { + mSlots[i].clear(); + } + } + mCurrentSlot = initialSlot; +} + +void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_ABS) { + bool newSlot = false; + if (mUsingSlotsProtocol) { + if (rawEvent->code == ABS_MT_SLOT) { + mCurrentSlot = rawEvent->value; + newSlot = true; + } + } else if (mCurrentSlot < 0) { + mCurrentSlot = 0; + } + + if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { +#if DEBUG_POINTERS + if (newSlot) { + ALOGW("MultiTouch device emitted invalid slot index %d but it " + "should be between 0 and %zd; ignoring this slot.", + mCurrentSlot, mSlotCount - 1); + } +#endif + } else { + Slot* slot = &mSlots[mCurrentSlot]; + + switch (rawEvent->code) { + case ABS_MT_POSITION_X: + slot->mInUse = true; + slot->mAbsMTPositionX = rawEvent->value; + break; + case ABS_MT_POSITION_Y: + slot->mInUse = true; + slot->mAbsMTPositionY = rawEvent->value; + break; + case ABS_MT_TOUCH_MAJOR: + slot->mInUse = true; + slot->mAbsMTTouchMajor = rawEvent->value; + break; + case ABS_MT_TOUCH_MINOR: + slot->mInUse = true; + slot->mAbsMTTouchMinor = rawEvent->value; + slot->mHaveAbsMTTouchMinor = true; + break; + case ABS_MT_WIDTH_MAJOR: + slot->mInUse = true; + slot->mAbsMTWidthMajor = rawEvent->value; + break; + case ABS_MT_WIDTH_MINOR: + slot->mInUse = true; + slot->mAbsMTWidthMinor = rawEvent->value; + slot->mHaveAbsMTWidthMinor = true; + break; + case ABS_MT_ORIENTATION: + slot->mInUse = true; + slot->mAbsMTOrientation = rawEvent->value; + break; + case ABS_MT_TRACKING_ID: + if (mUsingSlotsProtocol && rawEvent->value < 0) { + // The slot is no longer in use but it retains its previous contents, + // which may be reused for subsequent touches. + slot->mInUse = false; + } else { + slot->mInUse = true; + slot->mAbsMTTrackingId = rawEvent->value; + } + break; + case ABS_MT_PRESSURE: + slot->mInUse = true; + slot->mAbsMTPressure = rawEvent->value; + break; + case ABS_MT_DISTANCE: + slot->mInUse = true; + slot->mAbsMTDistance = rawEvent->value; + break; + case ABS_MT_TOOL_TYPE: + slot->mInUse = true; + slot->mAbsMTToolType = rawEvent->value; + slot->mHaveAbsMTToolType = true; + break; + } + } + } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { + // MultiTouch Sync: The driver has returned all data for *one* of the pointers. + mCurrentSlot += 1; + } else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) { + mDeviceTimestamp = rawEvent->value; + } +} + +void MultiTouchMotionAccumulator::finishSync() { + if (!mUsingSlotsProtocol) { + clearSlots(-1); + } +} + +bool MultiTouchMotionAccumulator::hasStylus() const { + return mHaveStylus; +} + +// --- MultiTouchMotionAccumulator::Slot --- + +MultiTouchMotionAccumulator::Slot::Slot() { + clear(); +} + +void MultiTouchMotionAccumulator::Slot::clear() { + mInUse = false; + mHaveAbsMTTouchMinor = false; + mHaveAbsMTWidthMinor = false; + mHaveAbsMTToolType = false; + mAbsMTPositionX = 0; + mAbsMTPositionY = 0; + mAbsMTTouchMajor = 0; + mAbsMTTouchMinor = 0; + mAbsMTWidthMajor = 0; + mAbsMTWidthMinor = 0; + mAbsMTOrientation = 0; + mAbsMTTrackingId = -1; + mAbsMTPressure = 0; + mAbsMTDistance = 0; + mAbsMTToolType = 0; +} + +int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { + if (mHaveAbsMTToolType) { + switch (mAbsMTToolType) { + case MT_TOOL_FINGER: + return AMOTION_EVENT_TOOL_TYPE_FINGER; + case MT_TOOL_PEN: + return AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + } + return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; +} + +// --- MultiTouchInputMapper --- + +MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : TouchInputMapper(device) {} + +MultiTouchInputMapper::~MultiTouchInputMapper() {} + +void MultiTouchInputMapper::reset(nsecs_t when) { + mMultiTouchMotionAccumulator.reset(getDevice()); + + mPointerIdBits.clear(); + + TouchInputMapper::reset(when); +} + +void MultiTouchInputMapper::process(const RawEvent* rawEvent) { + TouchInputMapper::process(rawEvent); + + mMultiTouchMotionAccumulator.process(rawEvent); +} + +void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { + size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); + size_t outCount = 0; + BitSet32 newPointerIdBits; + mHavePointerIds = true; + + for (size_t inIndex = 0; inIndex < inCount; inIndex++) { + const MultiTouchMotionAccumulator::Slot* inSlot = + mMultiTouchMotionAccumulator.getSlot(inIndex); + if (!inSlot->isInUse()) { + continue; + } + + if (outCount >= MAX_POINTERS) { +#if DEBUG_POINTERS + ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " + "ignoring the rest.", + getDeviceName().c_str(), MAX_POINTERS); +#endif + break; // too many fingers! + } + + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; + outPointer.x = inSlot->getX(); + outPointer.y = inSlot->getY(); + outPointer.pressure = inSlot->getPressure(); + outPointer.touchMajor = inSlot->getTouchMajor(); + outPointer.touchMinor = inSlot->getTouchMinor(); + outPointer.toolMajor = inSlot->getToolMajor(); + outPointer.toolMinor = inSlot->getToolMinor(); + outPointer.orientation = inSlot->getOrientation(); + outPointer.distance = inSlot->getDistance(); + outPointer.tiltX = 0; + outPointer.tiltY = 0; + + outPointer.toolType = inSlot->getToolType(); + if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + outPointer.toolType = mTouchButtonAccumulator.getToolType(); + if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + } + } + + bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && + (mTouchButtonAccumulator.isHovering() || + (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); + outPointer.isHovering = isHovering; + + // Assign pointer id using tracking id if available. + if (mHavePointerIds) { + int32_t trackingId = inSlot->getTrackingId(); + int32_t id = -1; + if (trackingId >= 0) { + for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) { + uint32_t n = idBits.clearFirstMarkedBit(); + if (mPointerTrackingIdMap[n] == trackingId) { + id = n; + } + } + + if (id < 0 && !mPointerIdBits.isFull()) { + id = mPointerIdBits.markFirstUnmarkedBit(); + mPointerTrackingIdMap[id] = trackingId; + } + } + if (id < 0) { + mHavePointerIds = false; + outState->rawPointerData.clearIdBits(); + newPointerIdBits.clear(); + } else { + outPointer.id = id; + outState->rawPointerData.idToIndex[id] = outCount; + outState->rawPointerData.markIdBit(id, isHovering); + newPointerIdBits.markBit(id); + } + } + outCount += 1; + } + + outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp(); + outState->rawPointerData.pointerCount = outCount; + mPointerIdBits = newPointerIdBits; + + mMultiTouchMotionAccumulator.finishSync(); +} + +void MultiTouchInputMapper::configureRawPointerAxes() { + TouchInputMapper::configureRawPointerAxes(); + + getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); + getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); + getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); + getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); + getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); + getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); + getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); + getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); + getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); + getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); + getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); + + if (mRawPointerAxes.trackingId.valid && mRawPointerAxes.slot.valid && + mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { + size_t slotCount = mRawPointerAxes.slot.maxValue + 1; + if (slotCount > MAX_SLOTS) { + ALOGW("MultiTouch Device %s reported %zu slots but the framework " + "only supports a maximum of %zu slots at this time.", + getDeviceName().c_str(), slotCount, MAX_SLOTS); + slotCount = MAX_SLOTS; + } + mMultiTouchMotionAccumulator.configure(getDevice(), slotCount, true /*usingSlotsProtocol*/); + } else { + mMultiTouchMotionAccumulator.configure(getDevice(), MAX_POINTERS, + false /*usingSlotsProtocol*/); + } +} + +bool MultiTouchInputMapper::hasStylus() const { + return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus(); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h new file mode 100644 index 0000000000..873dda1aec --- /dev/null +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.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_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H +#define _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H + +#include "TouchInputMapper.h" + +namespace android { + +/* Keeps track of the state of multi-touch protocol. */ +class MultiTouchMotionAccumulator { +public: + class Slot { + public: + inline bool isInUse() const { return mInUse; } + inline int32_t getX() const { return mAbsMTPositionX; } + inline int32_t getY() const { return mAbsMTPositionY; } + inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } + inline int32_t getTouchMinor() const { + return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; + } + inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } + inline int32_t getToolMinor() const { + return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; + } + inline int32_t getOrientation() const { return mAbsMTOrientation; } + inline int32_t getTrackingId() const { return mAbsMTTrackingId; } + inline int32_t getPressure() const { return mAbsMTPressure; } + inline int32_t getDistance() const { return mAbsMTDistance; } + inline int32_t getToolType() const; + + private: + friend class MultiTouchMotionAccumulator; + + bool mInUse; + bool mHaveAbsMTTouchMinor; + bool mHaveAbsMTWidthMinor; + bool mHaveAbsMTToolType; + + int32_t mAbsMTPositionX; + int32_t mAbsMTPositionY; + int32_t mAbsMTTouchMajor; + int32_t mAbsMTTouchMinor; + int32_t mAbsMTWidthMajor; + int32_t mAbsMTWidthMinor; + int32_t mAbsMTOrientation; + int32_t mAbsMTTrackingId; + int32_t mAbsMTPressure; + int32_t mAbsMTDistance; + int32_t mAbsMTToolType; + + Slot(); + void clear(); + }; + + MultiTouchMotionAccumulator(); + ~MultiTouchMotionAccumulator(); + + void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); + void reset(InputDevice* device); + void process(const RawEvent* rawEvent); + void finishSync(); + bool hasStylus() const; + + inline size_t getSlotCount() const { return mSlotCount; } + inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } + inline uint32_t getDeviceTimestamp() const { return mDeviceTimestamp; } + +private: + int32_t mCurrentSlot; + Slot* mSlots; + size_t mSlotCount; + bool mUsingSlotsProtocol; + bool mHaveStylus; + uint32_t mDeviceTimestamp; + + void clearSlots(int32_t initialSlot); +}; + +class MultiTouchInputMapper : public TouchInputMapper { +public: + explicit MultiTouchInputMapper(InputDevice* device); + virtual ~MultiTouchInputMapper(); + + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + +protected: + virtual void syncTouch(nsecs_t when, RawState* outState); + virtual void configureRawPointerAxes(); + virtual bool hasStylus() const; + +private: + MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; + + // Specifies the pointer id bits that are in use, and their associated tracking id. + BitSet32 mPointerIdBits; + int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; +}; + +} // namespace android + +#endif // _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp new file mode 100644 index 0000000000..803fdf3656 --- /dev/null +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -0,0 +1,134 @@ +/* + * 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 "Macros.h" + +#include "RotaryEncoderInputMapper.h" + +#include "CursorScrollAccumulator.h" + +namespace android { + +RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) + : InputMapper(device), mOrientation(DISPLAY_ORIENTATION_0) { + mSource = AINPUT_SOURCE_ROTARY_ENCODER; +} + +RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} + +uint32_t RotaryEncoderInputMapper::getSources() { + return mSource; +} + +void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { + float res = 0.0f; + if (!mDevice->getConfiguration().tryGetProperty(String8("device.res"), res)) { + ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); + } + if (!mDevice->getConfiguration().tryGetProperty(String8("device.scalingFactor"), + mScalingFactor)) { + ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," + "default to 1.0!\n"); + mScalingFactor = 1.0f; + } + info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, + res * mScalingFactor); + } +} + +void RotaryEncoderInputMapper::dump(std::string& dump) { + dump += INDENT2 "Rotary Encoder Input Mapper:\n"; + dump += StringPrintf(INDENT3 "HaveWheel: %s\n", + toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel())); +} + +void RotaryEncoderInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, + uint32_t changes) { + InputMapper::configure(when, config, changes); + if (!changes) { + mRotaryEncoderScrollAccumulator.configure(getDevice()); + } + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + std::optional<DisplayViewport> internalViewport = + config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + if (internalViewport) { + mOrientation = internalViewport->orientation; + } else { + mOrientation = DISPLAY_ORIENTATION_0; + } + } +} + +void RotaryEncoderInputMapper::reset(nsecs_t when) { + mRotaryEncoderScrollAccumulator.reset(getDevice()); + + InputMapper::reset(when); +} + +void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) { + mRotaryEncoderScrollAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void RotaryEncoderInputMapper::sync(nsecs_t when) { + PointerCoords pointerCoords; + pointerCoords.clear(); + + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + + float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); + bool scrolled = scroll != 0; + + // This is not a pointer, so it's not associated with a display. + int32_t displayId = ADISPLAY_ID_NONE; + + // Moving the rotary encoder should wake the device (if specified). + uint32_t policyFlags = 0; + if (scrolled && getDevice()->isExternal()) { + policyFlags |= POLICY_FLAG_WAKE; + } + + if (mOrientation == DISPLAY_ORIENTATION_180) { + scroll = -scroll; + } + + // Send motion event. + if (scrolled) { + int32_t metaState = mContext->getGlobalMetaState(); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); + + NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, + metaState, /* buttonState */ 0, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + 0, 0, 0, /* videoFrames */ {}); + getListener()->notifyMotion(&scrollArgs); + } + + mRotaryEncoderScrollAccumulator.finishSync(); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h new file mode 100644 index 0000000000..26488373bd --- /dev/null +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h @@ -0,0 +1,49 @@ +/* + * 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_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H +#define _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H + +#include "CursorScrollAccumulator.h" +#include "InputMapper.h" + +namespace android { + +class RotaryEncoderInputMapper : public InputMapper { +public: + explicit RotaryEncoderInputMapper(InputDevice* device); + virtual ~RotaryEncoderInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + +private: + CursorScrollAccumulator mRotaryEncoderScrollAccumulator; + + int32_t mSource; + float mScalingFactor; + int32_t mOrientation; + + void sync(nsecs_t when); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp new file mode 100644 index 0000000000..440d282686 --- /dev/null +++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp @@ -0,0 +1,85 @@ +/* + * 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 "SingleTouchInputMapper.h" + +namespace android { + +SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : TouchInputMapper(device) {} + +SingleTouchInputMapper::~SingleTouchInputMapper() {} + +void SingleTouchInputMapper::reset(nsecs_t when) { + mSingleTouchMotionAccumulator.reset(getDevice()); + + TouchInputMapper::reset(when); +} + +void SingleTouchInputMapper::process(const RawEvent* rawEvent) { + TouchInputMapper::process(rawEvent); + + mSingleTouchMotionAccumulator.process(rawEvent); +} + +void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { + if (mTouchButtonAccumulator.isToolActive()) { + outState->rawPointerData.pointerCount = 1; + outState->rawPointerData.idToIndex[0] = 0; + + bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && + (mTouchButtonAccumulator.isHovering() || + (mRawPointerAxes.pressure.valid && + mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); + outState->rawPointerData.markIdBit(0, isHovering); + + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; + outPointer.id = 0; + outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); + outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); + outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); + outPointer.touchMajor = 0; + outPointer.touchMinor = 0; + outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); + outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); + outPointer.orientation = 0; + outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); + outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); + outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); + outPointer.toolType = mTouchButtonAccumulator.getToolType(); + if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + } + outPointer.isHovering = isHovering; + } +} + +void SingleTouchInputMapper::configureRawPointerAxes() { + TouchInputMapper::configureRawPointerAxes(); + + getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); + getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); + getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); + getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); + getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); + getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); + getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); +} + +bool SingleTouchInputMapper::hasStylus() const { + return mTouchButtonAccumulator.hasStylus(); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h new file mode 100644 index 0000000000..d6b1455b68 --- /dev/null +++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.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_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H +#define _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H + +#include "SingleTouchMotionAccumulator.h" +#include "TouchInputMapper.h" + +namespace android { + +class SingleTouchInputMapper : public TouchInputMapper { +public: + explicit SingleTouchInputMapper(InputDevice* device); + virtual ~SingleTouchInputMapper(); + + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + +protected: + virtual void syncTouch(nsecs_t when, RawState* outState); + virtual void configureRawPointerAxes(); + virtual bool hasStylus() const; + +private: + SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; +}; + +} // namespace android + +#endif // _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp new file mode 100644 index 0000000000..4ff941f5cf --- /dev/null +++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp @@ -0,0 +1,76 @@ +/* + * 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 "Macros.h" + +#include "SwitchInputMapper.h" + +namespace android { + +SwitchInputMapper::SwitchInputMapper(InputDevice* device) + : InputMapper(device), mSwitchValues(0), mUpdatedSwitchMask(0) {} + +SwitchInputMapper::~SwitchInputMapper() {} + +uint32_t SwitchInputMapper::getSources() { + return AINPUT_SOURCE_SWITCH; +} + +void SwitchInputMapper::process(const RawEvent* rawEvent) { + switch (rawEvent->type) { + case EV_SW: + processSwitch(rawEvent->code, rawEvent->value); + break; + + case EV_SYN: + if (rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } + } +} + +void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { + if (switchCode >= 0 && switchCode < 32) { + if (switchValue) { + mSwitchValues |= 1 << switchCode; + } else { + mSwitchValues &= ~(1 << switchCode); + } + mUpdatedSwitchMask |= 1 << switchCode; + } +} + +void SwitchInputMapper::sync(nsecs_t when) { + if (mUpdatedSwitchMask) { + uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask; + NotifySwitchArgs args(mContext->getNextSequenceNum(), when, 0, updatedSwitchValues, + mUpdatedSwitchMask); + getListener()->notifySwitch(&args); + + mUpdatedSwitchMask = 0; + } +} + +int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { + return getEventHub()->getSwitchState(getDeviceId(), switchCode); +} + +void SwitchInputMapper::dump(std::string& dump) { + dump += INDENT2 "Switch Input Mapper:\n"; + dump += StringPrintf(INDENT3 "SwitchValues: %x\n", mSwitchValues); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.h b/services/inputflinger/reader/mapper/SwitchInputMapper.h new file mode 100644 index 0000000000..dd4bb9ed65 --- /dev/null +++ b/services/inputflinger/reader/mapper/SwitchInputMapper.h @@ -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. + */ + +#ifndef _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H +#define _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H + +#include "InputMapper.h" + +namespace android { + +class SwitchInputMapper : public InputMapper { +public: + explicit SwitchInputMapper(InputDevice* device); + virtual ~SwitchInputMapper(); + + virtual uint32_t getSources(); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + virtual void dump(std::string& dump); + +private: + uint32_t mSwitchValues; + uint32_t mUpdatedSwitchMask; + + void processSwitch(int32_t switchCode, int32_t switchValue); + void sync(nsecs_t when); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h new file mode 100644 index 0000000000..efa3d6d2b2 --- /dev/null +++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h @@ -0,0 +1,88 @@ +/* + * 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_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H +#define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H + +#include "EventHub.h" +#include "InputListener.h" +#include "InputReaderContext.h" + +#include <stdint.h> + +namespace android { + +// --- Static Definitions --- + +static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { + float temp; + switch (orientation) { + case DISPLAY_ORIENTATION_90: + temp = *deltaX; + *deltaX = *deltaY; + *deltaY = -temp; + break; + + case DISPLAY_ORIENTATION_180: + *deltaX = -*deltaX; + *deltaY = -*deltaY; + break; + + case DISPLAY_ORIENTATION_270: + temp = *deltaX; + *deltaX = -*deltaY; + *deltaY = temp; + break; + } +} + +// Returns true if the pointer should be reported as being down given the specified +// button states. This determines whether the event is reported as a touch event. +static bool isPointerDown(int32_t buttonState) { + return buttonState & + (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY | + AMOTION_EVENT_BUTTON_TERTIARY); +} + +static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nsecs_t when, + int32_t deviceId, uint32_t source, int32_t displayId, + uint32_t policyFlags, int32_t lastButtonState, + int32_t currentButtonState, int32_t buttonState, int32_t keyCode) { + if ((action == AKEY_EVENT_ACTION_DOWN && !(lastButtonState & buttonState) && + (currentButtonState & buttonState)) || + (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) && + !(currentButtonState & buttonState))) { + NotifyKeyArgs args(context->getNextSequenceNum(), when, deviceId, source, displayId, + policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when); + context->getListener()->notifyKey(&args); + } +} + +static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, nsecs_t when, + int32_t deviceId, uint32_t source, int32_t displayId, + uint32_t policyFlags, int32_t lastButtonState, + int32_t currentButtonState) { + synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags, + lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_BACK, + AKEYCODE_BACK); + synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags, + lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_FORWARD, + AKEYCODE_FORWARD); +} + +} // namespace android + +#endif // _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp new file mode 100644 index 0000000000..32ed97bffe --- /dev/null +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -0,0 +1,3909 @@ +/* + * 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 "Macros.h" + +#include "TouchInputMapper.h" + +#include "CursorButtonAccumulator.h" +#include "CursorScrollAccumulator.h" +#include "TouchButtonAccumulator.h" +#include "TouchCursorInputMapperCommon.h" + +#include <statslog.h> + +// How often to report input event statistics +static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60); + +namespace android { + +// --- Constants --- + +// Maximum amount of latency to add to touch events while waiting for data from an +// external stylus. +static constexpr nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); + +// Maximum amount of time to wait on touch data before pushing out new pressure data. +static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); + +// Artificial latency on synthetic events created from stylus data without corresponding touch +// data. +static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); + +// --- Static Definitions --- + +template <typename T> +inline static void swap(T& a, T& b) { + T temp = a; + a = b; + b = temp; +} + +static float calculateCommonVector(float a, float b) { + if (a > 0 && b > 0) { + return a < b ? a : b; + } else if (a < 0 && b < 0) { + return a > b ? a : b; + } else { + return 0; + } +} + +inline static float distance(float x1, float y1, float x2, float y2) { + return hypotf(x1 - x2, y1 - y2); +} + +inline static int32_t signExtendNybble(int32_t value) { + return value >= 8 ? value - 16 : value; +} + +// --- RawPointerAxes --- + +RawPointerAxes::RawPointerAxes() { + clear(); +} + +void RawPointerAxes::clear() { + x.clear(); + y.clear(); + pressure.clear(); + touchMajor.clear(); + touchMinor.clear(); + toolMajor.clear(); + toolMinor.clear(); + orientation.clear(); + distance.clear(); + tiltX.clear(); + tiltY.clear(); + trackingId.clear(); + slot.clear(); +} + +// --- RawPointerData --- + +RawPointerData::RawPointerData() { + clear(); +} + +void RawPointerData::clear() { + pointerCount = 0; + clearIdBits(); +} + +void RawPointerData::copyFrom(const RawPointerData& other) { + pointerCount = other.pointerCount; + hoveringIdBits = other.hoveringIdBits; + touchingIdBits = other.touchingIdBits; + + for (uint32_t i = 0; i < pointerCount; i++) { + pointers[i] = other.pointers[i]; + + int id = pointers[i].id; + idToIndex[id] = other.idToIndex[id]; + } +} + +void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { + float x = 0, y = 0; + uint32_t count = touchingIdBits.count(); + if (count) { + for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + const Pointer& pointer = pointerForId(id); + x += pointer.x; + y += pointer.y; + } + x /= count; + y /= count; + } + *outX = x; + *outY = y; +} + +// --- CookedPointerData --- + +CookedPointerData::CookedPointerData() { + clear(); +} + +void CookedPointerData::clear() { + pointerCount = 0; + hoveringIdBits.clear(); + touchingIdBits.clear(); +} + +void CookedPointerData::copyFrom(const CookedPointerData& other) { + pointerCount = other.pointerCount; + hoveringIdBits = other.hoveringIdBits; + touchingIdBits = other.touchingIdBits; + + for (uint32_t i = 0; i < pointerCount; i++) { + pointerProperties[i].copyFrom(other.pointerProperties[i]); + pointerCoords[i].copyFrom(other.pointerCoords[i]); + + int id = pointerProperties[i].id; + idToIndex[id] = other.idToIndex[id]; + } +} + +// --- TouchInputMapper --- + +TouchInputMapper::TouchInputMapper(InputDevice* device) + : InputMapper(device), + mSource(0), + mDeviceMode(DEVICE_MODE_DISABLED), + mSurfaceWidth(-1), + mSurfaceHeight(-1), + mSurfaceLeft(0), + mSurfaceTop(0), + mPhysicalWidth(-1), + mPhysicalHeight(-1), + mPhysicalLeft(0), + mPhysicalTop(0), + mSurfaceOrientation(DISPLAY_ORIENTATION_0) {} + +TouchInputMapper::~TouchInputMapper() {} + +uint32_t TouchInputMapper::getSources() { + return mSource; +} + +void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + if (mDeviceMode != DEVICE_MODE_DISABLED) { + info->addMotionRange(mOrientedRanges.x); + info->addMotionRange(mOrientedRanges.y); + info->addMotionRange(mOrientedRanges.pressure); + + if (mOrientedRanges.haveSize) { + info->addMotionRange(mOrientedRanges.size); + } + + if (mOrientedRanges.haveTouchSize) { + info->addMotionRange(mOrientedRanges.touchMajor); + info->addMotionRange(mOrientedRanges.touchMinor); + } + + if (mOrientedRanges.haveToolSize) { + info->addMotionRange(mOrientedRanges.toolMajor); + info->addMotionRange(mOrientedRanges.toolMinor); + } + + if (mOrientedRanges.haveOrientation) { + info->addMotionRange(mOrientedRanges.orientation); + } + + if (mOrientedRanges.haveDistance) { + info->addMotionRange(mOrientedRanges.distance); + } + + if (mOrientedRanges.haveTilt) { + info->addMotionRange(mOrientedRanges.tilt); + } + + if (mCursorScrollAccumulator.haveRelativeVWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, + 0.0f); + } + if (mCursorScrollAccumulator.haveRelativeHWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, + 0.0f); + } + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { + const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; + const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, + x.fuzz, x.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, + y.fuzz, y.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, + x.fuzz, x.resolution); + info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, + y.fuzz, y.resolution); + } + info->setButtonUnderPad(mParameters.hasButtonUnderPad); + } +} + +void TouchInputMapper::dump(std::string& dump) { + dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode)); + dumpParameters(dump); + dumpVirtualKeys(dump); + dumpRawPointerAxes(dump); + dumpCalibration(dump); + dumpAffineTransformation(dump); + dumpSurface(dump); + + dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n"); + dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate); + dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate); + dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale); + dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale); + dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision); + dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision); + dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); + dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale); + dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale); + dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); + dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); + dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); + dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); + dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); + dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); + dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); + + dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); + dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n", + mLastRawState.rawPointerData.pointerCount); + for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { + const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; + dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " + "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " + "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " + "toolType=%d, isHovering=%s\n", + i, pointer.id, pointer.x, pointer.y, pointer.pressure, + pointer.touchMajor, pointer.touchMinor, pointer.toolMajor, + pointer.toolMinor, pointer.orientation, pointer.tiltX, pointer.tiltY, + pointer.distance, pointer.toolType, toString(pointer.isHovering)); + } + + dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n", + mLastCookedState.buttonState); + dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n", + mLastCookedState.cookedPointerData.pointerCount); + for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { + const PointerProperties& pointerProperties = + mLastCookedState.cookedPointerData.pointerProperties[i]; + const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; + dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " + "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, " + "toolMinor=%0.3f, " + "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " + "toolType=%d, isHovering=%s\n", + i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), + pointerProperties.toolType, + toString(mLastCookedState.cookedPointerData.isHovering(i))); + } + + dump += INDENT3 "Stylus Fusion:\n"; + dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n", + toString(mExternalStylusConnected)); + dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); + dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", + mExternalStylusFusionTimeout); + dump += INDENT3 "External Stylus State:\n"; + dumpStylusState(dump, mExternalStylusState); + + if (mDeviceMode == DEVICE_MODE_POINTER) { + dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n"); + dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale); + dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale); + dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n", mPointerXZoomScale); + dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n", mPointerYZoomScale); + dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth); + } +} + +const char* TouchInputMapper::modeToString(DeviceMode deviceMode) { + switch (deviceMode) { + case DEVICE_MODE_DISABLED: + return "disabled"; + case DEVICE_MODE_DIRECT: + return "direct"; + case DEVICE_MODE_UNSCALED: + return "unscaled"; + case DEVICE_MODE_NAVIGATION: + return "navigation"; + case DEVICE_MODE_POINTER: + return "pointer"; + } + return "unknown"; +} + +void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, + uint32_t changes) { + InputMapper::configure(when, config, changes); + + mConfig = *config; + + if (!changes) { // first time only + // Configure basic parameters. + configureParameters(); + + // Configure common accumulators. + mCursorScrollAccumulator.configure(getDevice()); + mTouchButtonAccumulator.configure(getDevice()); + + // Configure absolute axis information. + configureRawPointerAxes(); + + // Prepare input device calibration. + parseCalibration(); + resolveCalibration(); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { + // Update location calibration to reflect current settings + updateAffineTransformation(); + } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { + // Update pointer speed. + mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); + mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); + mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); + } + + bool resetNeeded = false; + if (!changes || + (changes & + (InputReaderConfiguration::CHANGE_DISPLAY_INFO | + InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT | + InputReaderConfiguration::CHANGE_SHOW_TOUCHES | + InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { + // Configure device sources, surface dimensions, orientation and + // scaling factors. + configureSurface(when, &resetNeeded); + } + + if (changes && resetNeeded) { + // Send reset, unless this is the first time the device has been configured, + // in which case the reader will call reset itself after all mappers are ready. + getDevice()->notifyReset(when); + } +} + +void TouchInputMapper::resolveExternalStylusPresence() { + std::vector<InputDeviceInfo> devices; + mContext->getExternalStylusDevices(devices); + mExternalStylusConnected = !devices.empty(); + + if (!mExternalStylusConnected) { + resetExternalStylus(); + } +} + +void TouchInputMapper::configureParameters() { + // Use the pointer presentation mode for devices that do not support distinct + // multitouch. The spot-based presentation relies on being able to accurately + // locate two or more fingers on the touch pad. + mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) + ? Parameters::GESTURE_MODE_SINGLE_TOUCH + : Parameters::GESTURE_MODE_MULTI_TOUCH; + + String8 gestureModeString; + if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), + gestureModeString)) { + if (gestureModeString == "single-touch") { + mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH; + } else if (gestureModeString == "multi-touch") { + mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH; + } else if (gestureModeString != "default") { + ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); + } + } + + if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { + // The device is a touch screen. + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; + } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { + // The device is a pointing device like a track pad. + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; + } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) || + getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { + // The device is a cursor device with a touch pad attached. + // By default don't use the touch pad to move the pointer. + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else { + // The device is a touch pad of unknown purpose. + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; + } + + mParameters.hasButtonUnderPad = + getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD); + + String8 deviceTypeString; + if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), + deviceTypeString)) { + if (deviceTypeString == "touchScreen") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; + } else if (deviceTypeString == "touchPad") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else if (deviceTypeString == "touchNavigation") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; + } else if (deviceTypeString == "pointer") { + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; + } else if (deviceTypeString != "default") { + ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); + } + } + + mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; + getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), + mParameters.orientationAware); + + mParameters.hasAssociatedDisplay = false; + mParameters.associatedDisplayIsExternal = false; + if (mParameters.orientationAware || + mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN || + mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { + mParameters.hasAssociatedDisplay = true; + if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { + mParameters.associatedDisplayIsExternal = getDevice()->isExternal(); + String8 uniqueDisplayId; + getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"), + uniqueDisplayId); + mParameters.uniqueDisplayId = uniqueDisplayId.c_str(); + } + } + if (getDevice()->getAssociatedDisplayPort()) { + mParameters.hasAssociatedDisplay = true; + } + + // Initial downs on external touch devices should wake the device. + // Normally we don't do this for internal touch screens to prevent them from waking + // up in your pocket but you can enable it using the input device configuration. + mParameters.wake = getDevice()->isExternal(); + getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake); +} + +void TouchInputMapper::dumpParameters(std::string& dump) { + dump += INDENT3 "Parameters:\n"; + + switch (mParameters.gestureMode) { + case Parameters::GESTURE_MODE_SINGLE_TOUCH: + dump += INDENT4 "GestureMode: single-touch\n"; + break; + case Parameters::GESTURE_MODE_MULTI_TOUCH: + dump += INDENT4 "GestureMode: multi-touch\n"; + break; + default: + assert(false); + } + + switch (mParameters.deviceType) { + case Parameters::DEVICE_TYPE_TOUCH_SCREEN: + dump += INDENT4 "DeviceType: touchScreen\n"; + break; + case Parameters::DEVICE_TYPE_TOUCH_PAD: + dump += INDENT4 "DeviceType: touchPad\n"; + break; + case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: + dump += INDENT4 "DeviceType: touchNavigation\n"; + break; + case Parameters::DEVICE_TYPE_POINTER: + dump += INDENT4 "DeviceType: pointer\n"; + break; + default: + ALOG_ASSERT(false); + } + + dump += StringPrintf(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, " + "displayId='%s'\n", + toString(mParameters.hasAssociatedDisplay), + toString(mParameters.associatedDisplayIsExternal), + mParameters.uniqueDisplayId.c_str()); + dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); +} + +void TouchInputMapper::configureRawPointerAxes() { + mRawPointerAxes.clear(); +} + +void TouchInputMapper::dumpRawPointerAxes(std::string& dump) { + dump += INDENT3 "Raw Touch Axes:\n"; + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); +} + +bool TouchInputMapper::hasExternalStylus() const { + return mExternalStylusConnected; +} + +/** + * Determine which DisplayViewport to use. + * 1. If display port is specified, return the matching viewport. If matching viewport not + * found, then return. + * 2. If a device has associated display, get the matching viewport by either unique id or by + * the display type (internal or external). + * 3. Otherwise, use a non-display viewport. + */ +std::optional<DisplayViewport> TouchInputMapper::findViewport() { + if (mParameters.hasAssociatedDisplay) { + const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort(); + if (displayPort) { + // Find the viewport that contains the same port + std::optional<DisplayViewport> v = mConfig.getDisplayViewportByPort(*displayPort); + if (!v) { + ALOGW("Input device %s should be associated with display on port %" PRIu8 ", " + "but the corresponding viewport is not found.", + getDeviceName().c_str(), *displayPort); + } + return v; + } + + if (!mParameters.uniqueDisplayId.empty()) { + return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId); + } + + ViewportType viewportTypeToUse; + if (mParameters.associatedDisplayIsExternal) { + viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL; + } else { + viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL; + } + + std::optional<DisplayViewport> viewport = + mConfig.getDisplayViewportByType(viewportTypeToUse); + if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) { + ALOGW("Input device %s should be associated with external display, " + "fallback to internal one for the external viewport is not found.", + getDeviceName().c_str()); + viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL); + } + + return viewport; + } + + DisplayViewport newViewport; + // Raw width and height in the natural orientation. + int32_t rawWidth = mRawPointerAxes.getRawWidth(); + int32_t rawHeight = mRawPointerAxes.getRawHeight(); + newViewport.setNonDisplayViewport(rawWidth, rawHeight); + return std::make_optional(newViewport); +} + +void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { + int32_t oldDeviceMode = mDeviceMode; + + resolveExternalStylusPresence(); + + // Determine device mode. + if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && + mConfig.pointerGesturesEnabled) { + mSource = AINPUT_SOURCE_MOUSE; + mDeviceMode = DEVICE_MODE_POINTER; + if (hasStylus()) { + mSource |= AINPUT_SOURCE_STYLUS; + } + } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && + mParameters.hasAssociatedDisplay) { + mSource = AINPUT_SOURCE_TOUCHSCREEN; + mDeviceMode = DEVICE_MODE_DIRECT; + if (hasStylus()) { + mSource |= AINPUT_SOURCE_STYLUS; + } + if (hasExternalStylus()) { + mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; + } + } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { + mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; + mDeviceMode = DEVICE_MODE_NAVIGATION; + } else { + mSource = AINPUT_SOURCE_TOUCHPAD; + mDeviceMode = DEVICE_MODE_UNSCALED; + } + + // Ensure we have valid X and Y axes. + if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { + ALOGW("Touch device '%s' did not report support for X or Y axis! " + "The device will be inoperable.", + getDeviceName().c_str()); + mDeviceMode = DEVICE_MODE_DISABLED; + return; + } + + // Get associated display dimensions. + std::optional<DisplayViewport> newViewport = findViewport(); + if (!newViewport) { + ALOGI("Touch device '%s' could not query the properties of its associated " + "display. The device will be inoperable until the display size " + "becomes available.", + getDeviceName().c_str()); + mDeviceMode = DEVICE_MODE_DISABLED; + return; + } + + // Raw width and height in the natural orientation. + int32_t rawWidth = mRawPointerAxes.getRawWidth(); + int32_t rawHeight = mRawPointerAxes.getRawHeight(); + + bool viewportChanged = mViewport != *newViewport; + if (viewportChanged) { + mViewport = *newViewport; + + if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { + // Convert rotated viewport to natural surface coordinates. + int32_t naturalLogicalWidth, naturalLogicalHeight; + int32_t naturalPhysicalWidth, naturalPhysicalHeight; + int32_t naturalPhysicalLeft, naturalPhysicalTop; + int32_t naturalDeviceWidth, naturalDeviceHeight; + switch (mViewport.orientation) { + case DISPLAY_ORIENTATION_90: + naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; + naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; + naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; + naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; + naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; + naturalPhysicalTop = mViewport.physicalLeft; + naturalDeviceWidth = mViewport.deviceHeight; + naturalDeviceHeight = mViewport.deviceWidth; + break; + case DISPLAY_ORIENTATION_180: + naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; + naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; + naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; + naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; + naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; + naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; + naturalDeviceWidth = mViewport.deviceWidth; + naturalDeviceHeight = mViewport.deviceHeight; + break; + case DISPLAY_ORIENTATION_270: + naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; + naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; + naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; + naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; + naturalPhysicalLeft = mViewport.physicalTop; + naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; + naturalDeviceWidth = mViewport.deviceHeight; + naturalDeviceHeight = mViewport.deviceWidth; + break; + case DISPLAY_ORIENTATION_0: + default: + naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; + naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; + naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; + naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; + naturalPhysicalLeft = mViewport.physicalLeft; + naturalPhysicalTop = mViewport.physicalTop; + naturalDeviceWidth = mViewport.deviceWidth; + naturalDeviceHeight = mViewport.deviceHeight; + break; + } + + if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) { + ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str()); + naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight; + naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth; + } + + mPhysicalWidth = naturalPhysicalWidth; + mPhysicalHeight = naturalPhysicalHeight; + mPhysicalLeft = naturalPhysicalLeft; + mPhysicalTop = naturalPhysicalTop; + + mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; + mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; + mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; + mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; + + mSurfaceOrientation = + mParameters.orientationAware ? mViewport.orientation : DISPLAY_ORIENTATION_0; + } else { + mPhysicalWidth = rawWidth; + mPhysicalHeight = rawHeight; + mPhysicalLeft = 0; + mPhysicalTop = 0; + + mSurfaceWidth = rawWidth; + mSurfaceHeight = rawHeight; + mSurfaceLeft = 0; + mSurfaceTop = 0; + mSurfaceOrientation = DISPLAY_ORIENTATION_0; + } + } + + // If moving between pointer modes, need to reset some state. + bool deviceModeChanged = mDeviceMode != oldDeviceMode; + if (deviceModeChanged) { + mOrientedRanges.clear(); + } + + // Create or update pointer controller if needed. + if (mDeviceMode == DEVICE_MODE_POINTER || + (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { + if (mPointerController == nullptr || viewportChanged) { + mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + } + } else { + mPointerController.clear(); + } + + if (viewportChanged || deviceModeChanged) { + ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " + "display id %d", + getDeviceId(), getDeviceName().c_str(), mSurfaceWidth, mSurfaceHeight, + mSurfaceOrientation, mDeviceMode, mViewport.displayId); + + // Configure X and Y factors. + mXScale = float(mSurfaceWidth) / rawWidth; + mYScale = float(mSurfaceHeight) / rawHeight; + mXTranslate = -mSurfaceLeft; + mYTranslate = -mSurfaceTop; + mXPrecision = 1.0f / mXScale; + mYPrecision = 1.0f / mYScale; + + mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; + mOrientedRanges.x.source = mSource; + mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; + mOrientedRanges.y.source = mSource; + + configureVirtualKeys(); + + // Scale factor for terms that are not oriented in a particular axis. + // If the pixels are square then xScale == yScale otherwise we fake it + // by choosing an average. + mGeometricScale = avg(mXScale, mYScale); + + // Size of diagonal axis. + float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight); + + // Size factors. + if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { + if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) { + mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; + } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) { + mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; + } else { + mSizeScale = 0.0f; + } + + mOrientedRanges.haveTouchSize = true; + mOrientedRanges.haveToolSize = true; + mOrientedRanges.haveSize = true; + + mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; + mOrientedRanges.touchMajor.source = mSource; + mOrientedRanges.touchMajor.min = 0; + mOrientedRanges.touchMajor.max = diagonalSize; + mOrientedRanges.touchMajor.flat = 0; + mOrientedRanges.touchMajor.fuzz = 0; + mOrientedRanges.touchMajor.resolution = 0; + + mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; + mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; + + mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; + mOrientedRanges.toolMajor.source = mSource; + mOrientedRanges.toolMajor.min = 0; + mOrientedRanges.toolMajor.max = diagonalSize; + mOrientedRanges.toolMajor.flat = 0; + mOrientedRanges.toolMajor.fuzz = 0; + mOrientedRanges.toolMajor.resolution = 0; + + mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; + mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; + + mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; + mOrientedRanges.size.source = mSource; + mOrientedRanges.size.min = 0; + mOrientedRanges.size.max = 1.0; + mOrientedRanges.size.flat = 0; + mOrientedRanges.size.fuzz = 0; + mOrientedRanges.size.resolution = 0; + } else { + mSizeScale = 0.0f; + } + + // Pressure factors. + mPressureScale = 0; + float pressureMax = 1.0; + if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL || + mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { + if (mCalibration.havePressureScale) { + mPressureScale = mCalibration.pressureScale; + pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; + } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { + mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; + } + } + + mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; + mOrientedRanges.pressure.source = mSource; + mOrientedRanges.pressure.min = 0; + mOrientedRanges.pressure.max = pressureMax; + mOrientedRanges.pressure.flat = 0; + mOrientedRanges.pressure.fuzz = 0; + mOrientedRanges.pressure.resolution = 0; + + // Tilt + mTiltXCenter = 0; + mTiltXScale = 0; + mTiltYCenter = 0; + mTiltYScale = 0; + mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; + if (mHaveTilt) { + mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue); + mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue); + mTiltXScale = M_PI / 180; + mTiltYScale = M_PI / 180; + + mOrientedRanges.haveTilt = true; + + mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; + mOrientedRanges.tilt.source = mSource; + mOrientedRanges.tilt.min = 0; + mOrientedRanges.tilt.max = M_PI_2; + mOrientedRanges.tilt.flat = 0; + mOrientedRanges.tilt.fuzz = 0; + mOrientedRanges.tilt.resolution = 0; + } + + // Orientation + mOrientationScale = 0; + if (mHaveTilt) { + mOrientedRanges.haveOrientation = true; + + mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; + mOrientedRanges.orientation.source = mSource; + mOrientedRanges.orientation.min = -M_PI; + mOrientedRanges.orientation.max = M_PI; + mOrientedRanges.orientation.flat = 0; + mOrientedRanges.orientation.fuzz = 0; + mOrientedRanges.orientation.resolution = 0; + } else if (mCalibration.orientationCalibration != + Calibration::ORIENTATION_CALIBRATION_NONE) { + if (mCalibration.orientationCalibration == + Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { + if (mRawPointerAxes.orientation.valid) { + if (mRawPointerAxes.orientation.maxValue > 0) { + mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; + } else if (mRawPointerAxes.orientation.minValue < 0) { + mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; + } else { + mOrientationScale = 0; + } + } + } + + mOrientedRanges.haveOrientation = true; + + mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; + mOrientedRanges.orientation.source = mSource; + mOrientedRanges.orientation.min = -M_PI_2; + mOrientedRanges.orientation.max = M_PI_2; + mOrientedRanges.orientation.flat = 0; + mOrientedRanges.orientation.fuzz = 0; + mOrientedRanges.orientation.resolution = 0; + } + + // Distance + mDistanceScale = 0; + if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { + if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_SCALED) { + if (mCalibration.haveDistanceScale) { + mDistanceScale = mCalibration.distanceScale; + } else { + mDistanceScale = 1.0f; + } + } + + mOrientedRanges.haveDistance = true; + + mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; + mOrientedRanges.distance.source = mSource; + mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; + mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale; + mOrientedRanges.distance.flat = 0; + mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale; + mOrientedRanges.distance.resolution = 0; + } + + // Compute oriented precision, scales and ranges. + // Note that the maximum value reported is an inclusive maximum value so it is one + // unit less than the total width or height of surface. + switch (mSurfaceOrientation) { + case DISPLAY_ORIENTATION_90: + case DISPLAY_ORIENTATION_270: + mOrientedXPrecision = mYPrecision; + mOrientedYPrecision = mXPrecision; + + mOrientedRanges.x.min = mYTranslate; + mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1; + mOrientedRanges.x.flat = 0; + mOrientedRanges.x.fuzz = 0; + mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; + + mOrientedRanges.y.min = mXTranslate; + mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1; + mOrientedRanges.y.flat = 0; + mOrientedRanges.y.fuzz = 0; + mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; + break; + + default: + mOrientedXPrecision = mXPrecision; + mOrientedYPrecision = mYPrecision; + + mOrientedRanges.x.min = mXTranslate; + mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1; + mOrientedRanges.x.flat = 0; + mOrientedRanges.x.fuzz = 0; + mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; + + mOrientedRanges.y.min = mYTranslate; + mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1; + mOrientedRanges.y.flat = 0; + mOrientedRanges.y.fuzz = 0; + mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; + break; + } + + // Location + updateAffineTransformation(); + + if (mDeviceMode == DEVICE_MODE_POINTER) { + // Compute pointer gesture detection parameters. + float rawDiagonal = hypotf(rawWidth, rawHeight); + float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight); + + // Scale movements such that one whole swipe of the touch pad covers a + // given area relative to the diagonal size of the display when no acceleration + // is applied. + // Assume that the touch pad has a square aspect ratio such that movements in + // X and Y of the same number of raw units cover the same physical distance. + mPointerXMovementScale = + mConfig.pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; + mPointerYMovementScale = mPointerXMovementScale; + + // Scale zooms to cover a smaller range of the display than movements do. + // This value determines the area around the pointer that is affected by freeform + // pointer gestures. + mPointerXZoomScale = + mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; + mPointerYZoomScale = mPointerXZoomScale; + + // Max width between pointers to detect a swipe gesture is more than some fraction + // of the diagonal axis of the touch pad. Touches that are wider than this are + // translated into freeform gestures. + mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; + + // Abort current pointer usages because the state has changed. + abortPointerUsage(when, 0 /*policyFlags*/); + } + + // Inform the dispatcher about the changes. + *outResetNeeded = true; + bumpGeneration(); + } +} + +void TouchInputMapper::dumpSurface(std::string& dump) { + dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str()); + dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); + dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); + dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); + dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); + dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth); + dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight); + dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft); + dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop); + dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); +} + +void TouchInputMapper::configureVirtualKeys() { + std::vector<VirtualKeyDefinition> virtualKeyDefinitions; + getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); + + mVirtualKeys.clear(); + + if (virtualKeyDefinitions.size() == 0) { + return; + } + + int32_t touchScreenLeft = mRawPointerAxes.x.minValue; + int32_t touchScreenTop = mRawPointerAxes.y.minValue; + int32_t touchScreenWidth = mRawPointerAxes.getRawWidth(); + int32_t touchScreenHeight = mRawPointerAxes.getRawHeight(); + + for (const VirtualKeyDefinition& virtualKeyDefinition : virtualKeyDefinitions) { + VirtualKey virtualKey; + + virtualKey.scanCode = virtualKeyDefinition.scanCode; + int32_t keyCode; + int32_t dummyKeyMetaState; + uint32_t flags; + if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0, &keyCode, + &dummyKeyMetaState, &flags)) { + ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); + continue; // drop the key + } + + virtualKey.keyCode = keyCode; + virtualKey.flags = flags; + + // convert the key definition's display coordinates into touch coordinates for a hit box + int32_t halfWidth = virtualKeyDefinition.width / 2; + int32_t halfHeight = virtualKeyDefinition.height / 2; + + virtualKey.hitLeft = + (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mSurfaceWidth + + touchScreenLeft; + virtualKey.hitRight = + (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mSurfaceWidth + + touchScreenLeft; + virtualKey.hitTop = + (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mSurfaceHeight + + touchScreenTop; + virtualKey.hitBottom = + (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mSurfaceHeight + + touchScreenTop; + mVirtualKeys.push_back(virtualKey); + } +} + +void TouchInputMapper::dumpVirtualKeys(std::string& dump) { + if (!mVirtualKeys.empty()) { + dump += INDENT3 "Virtual Keys:\n"; + + for (size_t i = 0; i < mVirtualKeys.size(); i++) { + const VirtualKey& virtualKey = mVirtualKeys[i]; + dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, " + "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", + i, virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft, + virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); + } + } +} + +void TouchInputMapper::parseCalibration() { + const PropertyMap& in = getDevice()->getConfiguration(); + Calibration& out = mCalibration; + + // Size + out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; + String8 sizeCalibrationString; + if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { + if (sizeCalibrationString == "none") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; + } else if (sizeCalibrationString == "geometric") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; + } else if (sizeCalibrationString == "diameter") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; + } else if (sizeCalibrationString == "box") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX; + } else if (sizeCalibrationString == "area") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; + } else if (sizeCalibrationString != "default") { + ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string()); + } + } + + out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale); + out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias); + out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed); + + // Pressure + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; + String8 pressureCalibrationString; + if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { + if (pressureCalibrationString == "none") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; + } else if (pressureCalibrationString == "physical") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; + } else if (pressureCalibrationString == "amplitude") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; + } else if (pressureCalibrationString != "default") { + ALOGW("Invalid value for touch.pressure.calibration: '%s'", + pressureCalibrationString.string()); + } + } + + out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale); + + // Orientation + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; + String8 orientationCalibrationString; + if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { + if (orientationCalibrationString == "none") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; + } else if (orientationCalibrationString == "interpolated") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; + } else if (orientationCalibrationString == "vector") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; + } else if (orientationCalibrationString != "default") { + ALOGW("Invalid value for touch.orientation.calibration: '%s'", + orientationCalibrationString.string()); + } + } + + // Distance + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; + String8 distanceCalibrationString; + if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { + if (distanceCalibrationString == "none") { + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; + } else if (distanceCalibrationString == "scaled") { + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; + } else if (distanceCalibrationString != "default") { + ALOGW("Invalid value for touch.distance.calibration: '%s'", + distanceCalibrationString.string()); + } + } + + out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale); + + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; + String8 coverageCalibrationString; + if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { + if (coverageCalibrationString == "none") { + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; + } else if (coverageCalibrationString == "box") { + out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; + } else if (coverageCalibrationString != "default") { + ALOGW("Invalid value for touch.coverage.calibration: '%s'", + coverageCalibrationString.string()); + } + } +} + +void TouchInputMapper::resolveCalibration() { + // Size + if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { + if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { + mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; + } + } else { + mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; + } + + // Pressure + if (mRawPointerAxes.pressure.valid) { + if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { + mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; + } + } else { + mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; + } + + // Orientation + if (mRawPointerAxes.orientation.valid) { + if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { + mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; + } + } else { + mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; + } + + // Distance + if (mRawPointerAxes.distance.valid) { + if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { + mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; + } + } else { + mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; + } + + // Coverage + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { + mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; + } +} + +void TouchInputMapper::dumpCalibration(std::string& dump) { + dump += INDENT3 "Calibration:\n"; + + // Size + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_NONE: + dump += INDENT4 "touch.size.calibration: none\n"; + break; + case Calibration::SIZE_CALIBRATION_GEOMETRIC: + dump += INDENT4 "touch.size.calibration: geometric\n"; + break; + case Calibration::SIZE_CALIBRATION_DIAMETER: + dump += INDENT4 "touch.size.calibration: diameter\n"; + break; + case Calibration::SIZE_CALIBRATION_BOX: + dump += INDENT4 "touch.size.calibration: box\n"; + break; + case Calibration::SIZE_CALIBRATION_AREA: + dump += INDENT4 "touch.size.calibration: area\n"; + break; + default: + ALOG_ASSERT(false); + } + + if (mCalibration.haveSizeScale) { + dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale); + } + + if (mCalibration.haveSizeBias) { + dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias); + } + + if (mCalibration.haveSizeIsSummed) { + dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n", + toString(mCalibration.sizeIsSummed)); + } + + // Pressure + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_NONE: + dump += INDENT4 "touch.pressure.calibration: none\n"; + break; + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + dump += INDENT4 "touch.pressure.calibration: physical\n"; + break; + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + dump += INDENT4 "touch.pressure.calibration: amplitude\n"; + break; + default: + ALOG_ASSERT(false); + } + + if (mCalibration.havePressureScale) { + dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale); + } + + // Orientation + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_NONE: + dump += INDENT4 "touch.orientation.calibration: none\n"; + break; + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + dump += INDENT4 "touch.orientation.calibration: interpolated\n"; + break; + case Calibration::ORIENTATION_CALIBRATION_VECTOR: + dump += INDENT4 "touch.orientation.calibration: vector\n"; + break; + default: + ALOG_ASSERT(false); + } + + // Distance + switch (mCalibration.distanceCalibration) { + case Calibration::DISTANCE_CALIBRATION_NONE: + dump += INDENT4 "touch.distance.calibration: none\n"; + break; + case Calibration::DISTANCE_CALIBRATION_SCALED: + dump += INDENT4 "touch.distance.calibration: scaled\n"; + break; + default: + ALOG_ASSERT(false); + } + + if (mCalibration.haveDistanceScale) { + dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale); + } + + switch (mCalibration.coverageCalibration) { + case Calibration::COVERAGE_CALIBRATION_NONE: + dump += INDENT4 "touch.coverage.calibration: none\n"; + break; + case Calibration::COVERAGE_CALIBRATION_BOX: + dump += INDENT4 "touch.coverage.calibration: box\n"; + break; + default: + ALOG_ASSERT(false); + } +} + +void TouchInputMapper::dumpAffineTransformation(std::string& dump) { + dump += INDENT3 "Affine Transformation:\n"; + + dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale); + dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix); + dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset); + dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix); + dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale); + dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset); +} + +void TouchInputMapper::updateAffineTransformation() { + mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(), + mSurfaceOrientation); +} + +void TouchInputMapper::reset(nsecs_t when) { + mCursorButtonAccumulator.reset(getDevice()); + mCursorScrollAccumulator.reset(getDevice()); + mTouchButtonAccumulator.reset(getDevice()); + + mPointerVelocityControl.reset(); + mWheelXVelocityControl.reset(); + mWheelYVelocityControl.reset(); + + mRawStatesPending.clear(); + mCurrentRawState.clear(); + mCurrentCookedState.clear(); + mLastRawState.clear(); + mLastCookedState.clear(); + mPointerUsage = POINTER_USAGE_NONE; + mSentHoverEnter = false; + mHavePointerIds = false; + mCurrentMotionAborted = false; + mDownTime = 0; + + mCurrentVirtualKey.down = false; + + mPointerGesture.reset(); + mPointerSimple.reset(); + resetExternalStylus(); + + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + mPointerController->clearSpots(); + } + + InputMapper::reset(when); +} + +void TouchInputMapper::resetExternalStylus() { + mExternalStylusState.clear(); + mExternalStylusId = -1; + mExternalStylusFusionTimeout = LLONG_MAX; + mExternalStylusDataPending = false; +} + +void TouchInputMapper::clearStylusDataPendingFlags() { + mExternalStylusDataPending = false; + mExternalStylusFusionTimeout = LLONG_MAX; +} + +void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) { + nsecs_t now = systemTime(CLOCK_MONOTONIC); + nsecs_t latency = now - evdevTime; + mStatistics.addValue(nanoseconds_to_microseconds(latency)); + nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime; + if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) { + android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, mStatistics.min, + mStatistics.max, mStatistics.mean(), mStatistics.stdev(), + mStatistics.count); + mStatistics.reset(now); + } +} + +void TouchInputMapper::process(const RawEvent* rawEvent) { + mCursorButtonAccumulator.process(rawEvent); + mCursorScrollAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + reportEventForStatistics(rawEvent->when); + sync(rawEvent->when); + } +} + +void TouchInputMapper::sync(nsecs_t when) { + const RawState* last = + mRawStatesPending.empty() ? &mCurrentRawState : &mRawStatesPending.back(); + + // Push a new state. + mRawStatesPending.emplace_back(); + + RawState* next = &mRawStatesPending.back(); + next->clear(); + next->when = when; + + // Sync button state. + next->buttonState = + mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); + + // Sync scroll + next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); + next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); + mCursorScrollAccumulator.finishSync(); + + // Sync touch + syncTouch(when, next); + + // Assign pointer ids. + if (!mHavePointerIds) { + assignPointerIds(last, next); + } + +#if DEBUG_RAW_EVENTS + ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " + "hovering ids 0x%08x -> 0x%08x", + last->rawPointerData.pointerCount, next->rawPointerData.pointerCount, + last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value, + last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value); +#endif + + processRawTouches(false /*timeout*/); +} + +void TouchInputMapper::processRawTouches(bool timeout) { + if (mDeviceMode == DEVICE_MODE_DISABLED) { + // Drop all input if the device is disabled. + mCurrentRawState.clear(); + mRawStatesPending.clear(); + return; + } + + // Drain any pending touch states. The invariant here is that the mCurrentRawState is always + // valid and must go through the full cook and dispatch cycle. This ensures that anything + // touching the current state will only observe the events that have been dispatched to the + // rest of the pipeline. + const size_t N = mRawStatesPending.size(); + size_t count; + for (count = 0; count < N; count++) { + const RawState& next = mRawStatesPending[count]; + + // A failure to assign the stylus id means that we're waiting on stylus data + // and so should defer the rest of the pipeline. + if (assignExternalStylusId(next, timeout)) { + break; + } + + // All ready to go. + clearStylusDataPendingFlags(); + mCurrentRawState.copyFrom(next); + if (mCurrentRawState.when < mLastRawState.when) { + mCurrentRawState.when = mLastRawState.when; + } + cookAndDispatch(mCurrentRawState.when); + } + if (count != 0) { + mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count); + } + + if (mExternalStylusDataPending) { + if (timeout) { + nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; + clearStylusDataPendingFlags(); + mCurrentRawState.copyFrom(mLastRawState); +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, synthesizing event with new stylus data"); +#endif + cookAndDispatch(when); + } else if (mExternalStylusFusionTimeout == LLONG_MAX) { + mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT; + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + } + } +} + +void TouchInputMapper::cookAndDispatch(nsecs_t when) { + // Always start with a clean state. + mCurrentCookedState.clear(); + + // Apply stylus buttons to current raw state. + applyExternalStylusButtonState(when); + + // Handle policy on initial down or hover events. + bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 && + mCurrentRawState.rawPointerData.pointerCount != 0; + + uint32_t policyFlags = 0; + bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; + if (initialDown || buttonsPressed) { + // If this is a touch screen, hide the pointer on an initial down. + if (mDeviceMode == DEVICE_MODE_DIRECT) { + getContext()->fadePointer(); + } + + if (mParameters.wake) { + policyFlags |= POLICY_FLAG_WAKE; + } + } + + // Consume raw off-screen touches before cooking pointer data. + // If touches are consumed, subsequent code will not receive any pointer data. + if (consumeRawTouches(when, policyFlags)) { + mCurrentRawState.rawPointerData.clear(); + } + + // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure + // with cooked pointer data that has the same ids and indices as the raw data. + // The following code can use either the raw or cooked data, as needed. + cookPointerData(); + + // Apply stylus pressure to current cooked state. + applyExternalStylusTouchState(when); + + // Synthesize key down from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + mViewport.displayId, policyFlags, mLastCookedState.buttonState, + mCurrentCookedState.buttonState); + + // Dispatch the touches either directly or by translation through a pointer on screen. + if (mDeviceMode == DEVICE_MODE_POINTER) { + for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || + pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER || + pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mCurrentCookedState.fingerIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { + mCurrentCookedState.mouseIdBits.markBit(id); + } + } + for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || + pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); + } + } + + // Stylus takes precedence over all tools, then mouse, then finger. + PointerUsage pointerUsage = mPointerUsage; + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + mCurrentCookedState.mouseIdBits.clear(); + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_STYLUS; + } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_MOUSE; + } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || + isPointerDown(mCurrentRawState.buttonState)) { + pointerUsage = POINTER_USAGE_GESTURES; + } + + dispatchPointerUsage(when, policyFlags, pointerUsage); + } else { + if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches && + mPointerController != nullptr) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits, + mViewport.displayId); + } + + if (!mCurrentMotionAborted) { + dispatchButtonRelease(when, policyFlags); + dispatchHoverExit(when, policyFlags); + dispatchTouches(when, policyFlags); + dispatchHoverEnterAndMove(when, policyFlags); + dispatchButtonPress(when, policyFlags); + } + + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentMotionAborted = false; + } + } + + // Synthesize key up from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + mViewport.displayId, policyFlags, mLastCookedState.buttonState, + mCurrentCookedState.buttonState); + + // Clear some transient state. + mCurrentRawState.rawVScroll = 0; + mCurrentRawState.rawHScroll = 0; + + // Copy current touch to last touch in preparation for the next cycle. + mLastRawState.copyFrom(mCurrentRawState); + mLastCookedState.copyFrom(mCurrentCookedState); +} + +void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { + if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) { + mCurrentRawState.buttonState |= mExternalStylusState.buttons; + } +} + +void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { + CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData; + const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData; + + if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) { + float pressure = mExternalStylusState.pressure; + if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) { + const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId); + pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); + } + PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + + PointerProperties& properties = + currentPointerData.editPointerPropertiesWithId(mExternalStylusId); + if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + properties.toolType = mExternalStylusState.toolType; + } + } +} + +bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { + if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { + return false; + } + + const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 && + state.rawPointerData.pointerCount != 0; + if (initialDown) { + if (mExternalStylusState.pressure != 0.0f) { +#if DEBUG_STYLUS_FUSION + ALOGD("Have both stylus and touch data, beginning fusion"); +#endif + mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); + } else if (timeout) { +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, assuming touch is not a stylus."); +#endif + resetExternalStylus(); + } else { + if (mExternalStylusFusionTimeout == LLONG_MAX) { + mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT; + } +#if DEBUG_STYLUS_FUSION + ALOGD("No stylus data but stylus is connected, requesting timeout " + "(%" PRId64 "ms)", + mExternalStylusFusionTimeout); +#endif + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + return true; + } + } + + // Check if the stylus pointer has gone up. + if (mExternalStylusId != -1 && !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { +#if DEBUG_STYLUS_FUSION + ALOGD("Stylus pointer is going up"); +#endif + mExternalStylusId = -1; + } + + return false; +} + +void TouchInputMapper::timeoutExpired(nsecs_t when) { + if (mDeviceMode == DEVICE_MODE_POINTER) { + if (mPointerUsage == POINTER_USAGE_GESTURES) { + dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); + } + } else if (mDeviceMode == DEVICE_MODE_DIRECT) { + if (mExternalStylusFusionTimeout < when) { + processRawTouches(true /*timeout*/); + } else if (mExternalStylusFusionTimeout != LLONG_MAX) { + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + } + } +} + +void TouchInputMapper::updateExternalStylusState(const StylusState& state) { + mExternalStylusState.copyFrom(state); + if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) { + // We're either in the middle of a fused stream of data or we're waiting on data before + // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus + // data. + mExternalStylusDataPending = true; + processRawTouches(false /*timeout*/); + } +} + +bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { + // Check for release of a virtual key. + if (mCurrentVirtualKey.down) { + if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { + // Pointer went up while virtual key was down. + mCurrentVirtualKey.down = false; + if (!mCurrentVirtualKey.ignored) { +#if DEBUG_VIRTUAL_KEYS + ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", + mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); +#endif + dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); + } + return true; + } + + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); + if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { + // Pointer is still within the space of the virtual key. + return true; + } + } + + // Pointer left virtual key area or another pointer also went down. + // Send key cancellation but do not consume the touch yet. + // This is useful when the user swipes through from the virtual key area + // into the main display surface. + mCurrentVirtualKey.down = false; + if (!mCurrentVirtualKey.ignored) { +#if DEBUG_VIRTUAL_KEYS + ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, + mCurrentVirtualKey.scanCode); +#endif + dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | + AKEY_EVENT_FLAG_CANCELED); + } + } + + if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() && + !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { + // Pointer just went down. Check for virtual key press or off-screen touches. + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); + if (!isPointInsideSurface(pointer.x, pointer.y)) { + // If exactly one pointer went down, check for virtual key hit. + // Otherwise we will drop the entire stroke. + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { + const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); + if (virtualKey) { + mCurrentVirtualKey.down = true; + mCurrentVirtualKey.downTime = when; + mCurrentVirtualKey.keyCode = virtualKey->keyCode; + mCurrentVirtualKey.scanCode = virtualKey->scanCode; + mCurrentVirtualKey.ignored = + mContext->shouldDropVirtualKey(when, getDevice(), virtualKey->keyCode, + virtualKey->scanCode); + + if (!mCurrentVirtualKey.ignored) { +#if DEBUG_VIRTUAL_KEYS + ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", + mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); +#endif + dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_DOWN, + AKEY_EVENT_FLAG_FROM_SYSTEM | + AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); + } + } + } + return true; + } + } + + // Disable all virtual key touches that happen within a short time interval of the + // most recent touch within the screen area. The idea is to filter out stray + // virtual key presses when interacting with the touch screen. + // + // Problems we're trying to solve: + // + // 1. While scrolling a list or dragging the window shade, the user swipes down into a + // virtual key area that is implemented by a separate touch panel and accidentally + // triggers a virtual key. + // + // 2. While typing in the on screen keyboard, the user taps slightly outside the screen + // area and accidentally triggers a virtual key. This often happens when virtual keys + // are layed out below the screen near to where the on screen keyboard's space bar + // is displayed. + if (mConfig.virtualKeyQuietTime > 0 && + !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { + mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); + } + return false; +} + +void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, + int32_t keyEventAction, int32_t keyEventFlags) { + int32_t keyCode = mCurrentVirtualKey.keyCode; + int32_t scanCode = mCurrentVirtualKey.scanCode; + nsecs_t downTime = mCurrentVirtualKey.downTime; + int32_t metaState = mContext->getGlobalMetaState(); + policyFlags |= POLICY_FLAG_VIRTUAL; + + NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, + mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode, + scanCode, metaState, downTime); + getListener()->notifyKey(&args); +} + +void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) { + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + if (!currentIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentCookedState.buttonState; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mCurrentMotionAborted = true; + } +} + +void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentCookedState.buttonState; + + if (currentIdBits == lastIdBits) { + if (!currentIdBits.isEmpty()) { + // No pointer id changes so this is a move event. + // The listener takes care of batching moves so we don't have to deal with that here. + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } + } else { + // There may be pointers going up and pointers going down and pointers moving + // all at the same time. + BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); + BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); + BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); + BitSet32 dispatchedIdBits(lastIdBits.value); + + // Update last coordinates of pointers that have moved so that we observe the new + // pointer positions at the same time as other pointers that have just gone up. + bool moveNeeded = + updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, moveIdBits); + if (buttonState != mLastCookedState.buttonState) { + moveNeeded = true; + } + + // Dispatch pointer up events. + while (!upIdBits.isEmpty()) { + uint32_t upId = upIdBits.clearFirstMarkedBit(); + + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, + metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + dispatchedIdBits.clearBit(upId); + } + + // Dispatch move events if any of the remaining pointers moved from their old locations. + // Although applications receive new locations as part of individual pointer up + // events, they do not generally handle them except when presented in a move event. + if (moveNeeded && !moveIdBits.isEmpty()) { + ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + buttonState, 0, mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } + + // Dispatch pointer down events using the new pointer locations. + while (!downIdBits.isEmpty()) { + uint32_t downId = downIdBits.clearFirstMarkedBit(); + dispatchedIdBits.markBit(downId); + + if (dispatchedIdBits.count() == 1) { + // First pointer is going down. Set down time. + mDownTime = when; + } + + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, + metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, + downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } + } +} + +void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { + if (mSentHoverEnter && + (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() || + !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { + int32_t metaState = getContext()->getGlobalMetaState(); + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, + mLastCookedState.buttonState, 0, mLastCookedState.deviceTimestamp, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, + mOrientedYPrecision, mDownTime); + mSentHoverEnter = false; + } +} + +void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { + if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() && + !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + if (!mSentHoverEnter) { + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, + metaState, mCurrentRawState.buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mSentHoverEnter = true; + } + + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, 0, mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) { + BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState); + const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData); + const int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mLastCookedState.buttonState; + while (!releasedButtons.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit()); + buttonState &= ~actionButton; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_RELEASE, + actionButton, 0, metaState, buttonState, 0, + mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) { + BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState); + const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData); + const int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mLastCookedState.buttonState; + while (!pressedButtons.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit()); + buttonState |= actionButton; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, + 0, metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) { + if (!cookedPointerData.touchingIdBits.isEmpty()) { + return cookedPointerData.touchingIdBits; + } + return cookedPointerData.hoveringIdBits; +} + +void TouchInputMapper::cookPointerData() { + uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; + + mCurrentCookedState.cookedPointerData.clear(); + mCurrentCookedState.deviceTimestamp = mCurrentRawState.deviceTimestamp; + mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; + mCurrentCookedState.cookedPointerData.hoveringIdBits = + mCurrentRawState.rawPointerData.hoveringIdBits; + mCurrentCookedState.cookedPointerData.touchingIdBits = + mCurrentRawState.rawPointerData.touchingIdBits; + + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentCookedState.buttonState = 0; + } else { + mCurrentCookedState.buttonState = mCurrentRawState.buttonState; + } + + // Walk through the the active pointers and map device coordinates onto + // surface coordinates and adjust for display orientation. + for (uint32_t i = 0; i < currentPointerCount; i++) { + const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; + + // Size + float touchMajor, touchMinor, toolMajor, toolMinor, size; + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_GEOMETRIC: + case Calibration::SIZE_CALIBRATION_DIAMETER: + case Calibration::SIZE_CALIBRATION_BOX: + case Calibration::SIZE_CALIBRATION_AREA: + if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { + touchMajor = in.touchMajor; + touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; + toolMajor = in.toolMajor; + toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; + size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) + : in.touchMajor; + } else if (mRawPointerAxes.touchMajor.valid) { + toolMajor = touchMajor = in.touchMajor; + toolMinor = touchMinor = + mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; + size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) + : in.touchMajor; + } else if (mRawPointerAxes.toolMajor.valid) { + touchMajor = toolMajor = in.toolMajor; + touchMinor = toolMinor = + mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; + size = mRawPointerAxes.toolMinor.valid ? avg(in.toolMajor, in.toolMinor) + : in.toolMajor; + } else { + ALOG_ASSERT(false, + "No touch or tool axes. " + "Size calibration should have been resolved to NONE."); + touchMajor = 0; + touchMinor = 0; + toolMajor = 0; + toolMinor = 0; + size = 0; + } + + if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { + uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count(); + if (touchingCount > 1) { + touchMajor /= touchingCount; + touchMinor /= touchingCount; + toolMajor /= touchingCount; + toolMinor /= touchingCount; + size /= touchingCount; + } + } + + if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { + touchMajor *= mGeometricScale; + touchMinor *= mGeometricScale; + toolMajor *= mGeometricScale; + toolMinor *= mGeometricScale; + } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { + touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; + touchMinor = touchMajor; + toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; + toolMinor = toolMajor; + } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { + touchMinor = touchMajor; + toolMinor = toolMajor; + } + + mCalibration.applySizeScaleAndBias(&touchMajor); + mCalibration.applySizeScaleAndBias(&touchMinor); + mCalibration.applySizeScaleAndBias(&toolMajor); + mCalibration.applySizeScaleAndBias(&toolMinor); + size *= mSizeScale; + break; + default: + touchMajor = 0; + touchMinor = 0; + toolMajor = 0; + toolMinor = 0; + size = 0; + break; + } + + // Pressure + float pressure; + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + pressure = in.pressure * mPressureScale; + break; + default: + pressure = in.isHovering ? 0 : 1; + break; + } + + // Tilt and Orientation + float tilt; + float orientation; + if (mHaveTilt) { + float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; + float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; + orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); + tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); + } else { + tilt = 0; + + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + orientation = in.orientation * mOrientationScale; + break; + case Calibration::ORIENTATION_CALIBRATION_VECTOR: { + int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); + int32_t c2 = signExtendNybble(in.orientation & 0x0f); + if (c1 != 0 || c2 != 0) { + orientation = atan2f(c1, c2) * 0.5f; + float confidence = hypotf(c1, c2); + float scale = 1.0f + confidence / 16.0f; + touchMajor *= scale; + touchMinor /= scale; + toolMajor *= scale; + toolMinor /= scale; + } else { + orientation = 0; + } + break; + } + default: + orientation = 0; + } + } + + // Distance + float distance; + switch (mCalibration.distanceCalibration) { + case Calibration::DISTANCE_CALIBRATION_SCALED: + distance = in.distance * mDistanceScale; + break; + default: + distance = 0; + } + + // Coverage + int32_t rawLeft, rawTop, rawRight, rawBottom; + switch (mCalibration.coverageCalibration) { + case Calibration::COVERAGE_CALIBRATION_BOX: + rawLeft = (in.toolMinor & 0xffff0000) >> 16; + rawRight = in.toolMinor & 0x0000ffff; + rawBottom = in.toolMajor & 0x0000ffff; + rawTop = (in.toolMajor & 0xffff0000) >> 16; + break; + default: + rawLeft = rawTop = rawRight = rawBottom = 0; + break; + } + + // Adjust X,Y coords for device calibration + // TODO: Adjust coverage coords? + float xTransformed = in.x, yTransformed = in.y; + mAffineTransform.applyTo(xTransformed, yTransformed); + + // Adjust X, Y, and coverage coords for surface orientation. + float x, y; + float left, top, right, bottom; + + switch (mSurfaceOrientation) { + case DISPLAY_ORIENTATION_90: + x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate; + left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; + top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; + orientation -= M_PI_2; + if (mOrientedRanges.haveOrientation && + orientation < mOrientedRanges.orientation.min) { + orientation += + (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + } + break; + case DISPLAY_ORIENTATION_180: + x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale; + y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate; + left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; + right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; + bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; + top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; + orientation -= M_PI; + if (mOrientedRanges.haveOrientation && + orientation < mOrientedRanges.orientation.min) { + orientation += + (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + } + break; + case DISPLAY_ORIENTATION_270: + x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale; + y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; + right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; + bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + orientation += M_PI_2; + if (mOrientedRanges.haveOrientation && + orientation > mOrientedRanges.orientation.max) { + orientation -= + (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + } + break; + default: + x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; + bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; + break; + } + + // Write output coords. + PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; + out.clear(); + out.setAxisValue(AMOTION_EVENT_AXIS_X, x); + out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); + out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); + out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); + out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); + out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); + out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); + if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); + out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); + } else { + out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); + out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); + } + + // Write output properties. + PointerProperties& properties = mCurrentCookedState.cookedPointerData.pointerProperties[i]; + uint32_t id = in.id; + properties.clear(); + properties.id = id; + properties.toolType = in.toolType; + + // Write id index. + mCurrentCookedState.cookedPointerData.idToIndex[id] = i; + } +} + +void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, + PointerUsage pointerUsage) { + if (pointerUsage != mPointerUsage) { + abortPointerUsage(when, policyFlags); + mPointerUsage = pointerUsage; + } + + switch (mPointerUsage) { + case POINTER_USAGE_GESTURES: + dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); + break; + case POINTER_USAGE_STYLUS: + dispatchPointerStylus(when, policyFlags); + break; + case POINTER_USAGE_MOUSE: + dispatchPointerMouse(when, policyFlags); + break; + default: + break; + } +} + +void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { + switch (mPointerUsage) { + case POINTER_USAGE_GESTURES: + abortPointerGestures(when, policyFlags); + break; + case POINTER_USAGE_STYLUS: + abortPointerStylus(when, policyFlags); + break; + case POINTER_USAGE_MOUSE: + abortPointerMouse(when, policyFlags); + break; + default: + break; + } + + mPointerUsage = POINTER_USAGE_NONE; +} + +void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) { + // Update current gesture coordinates. + bool cancelPreviousGesture, finishPreviousGesture; + bool sendEvents = + preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture, isTimeout); + if (!sendEvents) { + return; + } + if (finishPreviousGesture) { + cancelPreviousGesture = false; + } + + // Update the pointer presentation and spots. + if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + if (finishPreviousGesture || cancelPreviousGesture) { + mPointerController->clearSpots(); + } + + if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { + mPointerController->setSpots(mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, + mPointerController->getDisplayId()); + } + } else { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + } + + // Show or hide the pointer if needed. + switch (mPointerGesture.currentGestureMode) { + case PointerGesture::NEUTRAL: + case PointerGesture::QUIET: + if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH && + mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) { + // Remind the user of where the pointer is after finishing a gesture with spots. + mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); + } + break; + case PointerGesture::TAP: + case PointerGesture::TAP_DRAG: + case PointerGesture::BUTTON_CLICK_OR_DRAG: + case PointerGesture::HOVER: + case PointerGesture::PRESS: + case PointerGesture::SWIPE: + // Unfade the pointer when the current gesture manipulates the + // area directly under the pointer. + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + break; + case PointerGesture::FREEFORM: + // Fade the pointer when the current gesture manipulates a different + // area and there are spots to guide the user experience. + if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } else { + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } + break; + } + + // Send events! + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentCookedState.buttonState; + + // Update last coordinates of pointers that have moved so that we observe the new + // pointer positions at the same time as other pointers that have just gone up. + bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP || + mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG || + mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG || + mPointerGesture.currentGestureMode == PointerGesture::PRESS || + mPointerGesture.currentGestureMode == PointerGesture::SWIPE || + mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; + bool moveNeeded = false; + if (down && !cancelPreviousGesture && !finishPreviousGesture && + !mPointerGesture.lastGestureIdBits.isEmpty() && + !mPointerGesture.currentGestureIdBits.isEmpty()) { + BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value & + mPointerGesture.lastGestureIdBits.value); + moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.lastGestureProperties, + mPointerGesture.lastGestureCoords, + mPointerGesture.lastGestureIdToIndex, movedGestureIdBits); + if (buttonState != mLastCookedState.buttonState) { + moveNeeded = true; + } + } + + // Send motion events for all pointers that went up or were canceled. + BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); + if (!dispatchedGestureIdBits.isEmpty()) { + if (cancelPreviousGesture) { + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, + mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, + mPointerGesture.downTime); + + dispatchedGestureIdBits.clear(); + } else { + BitSet32 upGestureIdBits; + if (finishPreviousGesture) { + upGestureIdBits = dispatchedGestureIdBits; + } else { + upGestureIdBits.value = + dispatchedGestureIdBits.value & ~mPointerGesture.currentGestureIdBits.value; + } + while (!upGestureIdBits.isEmpty()) { + uint32_t id = upGestureIdBits.clearFirstMarkedBit(); + + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, mPointerGesture.lastGestureProperties, + mPointerGesture.lastGestureCoords, + mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0, + 0, mPointerGesture.downTime); + + dispatchedGestureIdBits.clearBit(id); + } + } + } + + // Send motion events for all pointers that moved. + if (moveNeeded) { + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, + mPointerGesture.downTime); + } + + // Send motion events for all pointers that went down. + if (down) { + BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value & + ~dispatchedGestureIdBits.value); + while (!downGestureIdBits.isEmpty()) { + uint32_t id = downGestureIdBits.clearFirstMarkedBit(); + dispatchedGestureIdBits.markBit(id); + + if (dispatchedGestureIdBits.count() == 1) { + mPointerGesture.downTime = when; + } + + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, + metaState, buttonState, 0, + /* deviceTimestamp */ 0, mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0, + 0, mPointerGesture.downTime); + } + } + + // Send motion events for hover. + if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + mPointerGesture.currentGestureProperties, + mPointerGesture.currentGestureCoords, + mPointerGesture.currentGestureIdToIndex, + mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime); + } else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) { + // Synthesize a hover move event after all pointers go up to indicate that + // the pointer is hovering again even if the user is not currently touching + // the touch pad. This ensures that a view will receive a fresh hover enter + // event after a tap. + float x, y; + mPointerController->getPosition(&x, &y); + + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + PointerCoords pointerCoords; + pointerCoords.clear(); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + + const int32_t displayId = mPointerController->getDisplayId(); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, + mPointerGesture.downTime, /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + // Update state. + mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; + if (!down) { + mPointerGesture.lastGestureIdBits.clear(); + } else { + mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; + for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + mPointerGesture.lastGestureProperties[index].copyFrom( + mPointerGesture.currentGestureProperties[index]); + mPointerGesture.lastGestureCoords[index].copyFrom( + mPointerGesture.currentGestureCoords[index]); + mPointerGesture.lastGestureIdToIndex[id] = index; + } + } +} + +void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { + // Cancel previously dispatches pointers. + if (!mPointerGesture.lastGestureIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentRawState.buttonState; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, + buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, + mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, + mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); + } + + // Reset the current pointer gesture. + mPointerGesture.reset(); + mPointerVelocityControl.reset(); + + // Remove any current spots. + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + mPointerController->clearSpots(); + } +} + +bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, + bool* outFinishPreviousGesture, bool isTimeout) { + *outCancelPreviousGesture = false; + *outFinishPreviousGesture = false; + + // Handle TAP timeout. + if (isTimeout) { +#if DEBUG_GESTURES + ALOGD("Gestures: Processing timeout"); +#endif + + if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { + if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { + // The tap/drag timeout has not yet expired. + getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + + mConfig.pointerGestureTapDragInterval); + } else { + // The tap is finished. +#if DEBUG_GESTURES + ALOGD("Gestures: TAP finished"); +#endif + *outFinishPreviousGesture = true; + + mPointerGesture.activeGestureId = -1; + mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; + mPointerGesture.currentGestureIdBits.clear(); + + mPointerVelocityControl.reset(); + return true; + } + } + + // We did not handle this timeout. + return false; + } + + const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); + const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); + + // Update the velocity tracker. + { + VelocityTracker::Position positions[MAX_POINTERS]; + uint32_t count = 0; + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + positions[count].x = pointer.x * mPointerXMovementScale; + positions[count].y = pointer.y * mPointerYMovementScale; + } + mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits, + positions); + } + + // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning + // to NEUTRAL, then we should not generate tap event. + if (mPointerGesture.lastGestureMode != PointerGesture::HOVER && + mPointerGesture.lastGestureMode != PointerGesture::TAP && + mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) { + mPointerGesture.resetTap(); + } + + // Pick a new active touch id if needed. + // Choose an arbitrary pointer that just went down, if there is one. + // Otherwise choose an arbitrary remaining pointer. + // This guarantees we always have an active touch id when there is at least one pointer. + // We keep the same active touch id for as long as possible. + int32_t lastActiveTouchId = mPointerGesture.activeTouchId; + int32_t activeTouchId = lastActiveTouchId; + if (activeTouchId < 0) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { + activeTouchId = mPointerGesture.activeTouchId = + mCurrentCookedState.fingerIdBits.firstMarkedBit(); + mPointerGesture.firstTouchTime = when; + } + } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { + activeTouchId = mPointerGesture.activeTouchId = + mCurrentCookedState.fingerIdBits.firstMarkedBit(); + } else { + activeTouchId = mPointerGesture.activeTouchId = -1; + } + } + + // Determine whether we are in quiet time. + bool isQuietTime = false; + if (activeTouchId < 0) { + mPointerGesture.resetQuietTime(); + } else { + isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; + if (!isQuietTime) { + if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS || + mPointerGesture.lastGestureMode == PointerGesture::SWIPE || + mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) && + currentFingerCount < 2) { + // Enter quiet time when exiting swipe or freeform state. + // This is to prevent accidentally entering the hover state and flinging the + // pointer when finishing a swipe and there is still one pointer left onscreen. + isQuietTime = true; + } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG && + currentFingerCount >= 2 && !isPointerDown(mCurrentRawState.buttonState)) { + // Enter quiet time when releasing the button and there are still two or more + // fingers down. This may indicate that one finger was used to press the button + // but it has not gone up yet. + isQuietTime = true; + } + if (isQuietTime) { + mPointerGesture.quietTime = when; + } + } + } + + // Switch states based on button and pointer state. + if (isQuietTime) { + // Case 1: Quiet time. (QUIET) +#if DEBUG_GESTURES + ALOGD("Gestures: QUIET for next %0.3fms", + (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * 0.000001f); +#endif + if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { + *outFinishPreviousGesture = true; + } + + mPointerGesture.activeGestureId = -1; + mPointerGesture.currentGestureMode = PointerGesture::QUIET; + mPointerGesture.currentGestureIdBits.clear(); + + mPointerVelocityControl.reset(); + } else if (isPointerDown(mCurrentRawState.buttonState)) { + // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) + // The pointer follows the active touch point. + // Emit DOWN, MOVE, UP events at the pointer location. + // + // Only the active touch matters; other fingers are ignored. This policy helps + // to handle the case where the user places a second finger on the touch pad + // to apply the necessary force to depress an integrated button below the surface. + // We don't want the second finger to be delivered to applications. + // + // For this to work well, we need to make sure to track the pointer that is really + // active. If the user first puts one finger down to click then adds another + // finger to drag then the active pointer should switch to the finger that is + // being dragged. +#if DEBUG_GESTURES + ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " + "currentFingerCount=%d", + activeTouchId, currentFingerCount); +#endif + // Reset state when just starting. + if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { + *outFinishPreviousGesture = true; + mPointerGesture.activeGestureId = 0; + } + + // Switch pointers if needed. + // Find the fastest pointer and follow it. + if (activeTouchId >= 0 && currentFingerCount > 1) { + int32_t bestId = -1; + float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + float vx, vy; + if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { + float speed = hypotf(vx, vy); + if (speed > bestSpeed) { + bestId = id; + bestSpeed = speed; + } + } + } + if (bestId >= 0 && bestId != activeTouchId) { + mPointerGesture.activeTouchId = activeTouchId = bestId; +#if DEBUG_GESTURES + ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " + "bestId=%d, bestSpeed=%0.3f", + bestId, bestSpeed); +#endif + } + } + + float deltaX = 0, deltaY = 0; + if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { + const RawPointerData::Pointer& currentPointer = + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); + const RawPointerData::Pointer& lastPointer = + mLastRawState.rawPointerData.pointerForId(activeTouchId); + deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; + deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + // Move the pointer using a relative motion. + // When using spots, the click will occur at the position of the anchor + // spot and all other spots will move there. + mPointerController->move(deltaX, deltaY); + } else { + mPointerVelocityControl.reset(); + } + + float x, y; + mPointerController->getPosition(&x, &y); + + mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + } else if (currentFingerCount == 0) { + // Case 3. No fingers down and button is not pressed. (NEUTRAL) + if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { + *outFinishPreviousGesture = true; + } + + // Watch for taps coming out of HOVER or TAP_DRAG mode. + // Checking for taps after TAP_DRAG allows us to detect double-taps. + bool tapped = false; + if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER || + mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) && + lastFingerCount == 1) { + if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { + float x, y; + mPointerController->getPosition(&x, &y); + if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && + fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { +#if DEBUG_GESTURES + ALOGD("Gestures: TAP"); +#endif + + mPointerGesture.tapUpTime = when; + getContext()->requestTimeoutAtTime(when + + mConfig.pointerGestureTapDragInterval); + + mPointerGesture.activeGestureId = 0; + mPointerGesture.currentGestureMode = PointerGesture::TAP; + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = + mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, + mPointerGesture.tapX); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, + mPointerGesture.tapY); + mPointerGesture.currentGestureCoords[0] + .setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + + tapped = true; + } else { +#if DEBUG_GESTURES + ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", x - mPointerGesture.tapX, + y - mPointerGesture.tapY); +#endif + } + } else { +#if DEBUG_GESTURES + if (mPointerGesture.tapDownTime != LLONG_MIN) { + ALOGD("Gestures: Not a TAP, %0.3fms since down", + (when - mPointerGesture.tapDownTime) * 0.000001f); + } else { + ALOGD("Gestures: Not a TAP, incompatible mode transitions"); + } +#endif + } + } + + mPointerVelocityControl.reset(); + + if (!tapped) { +#if DEBUG_GESTURES + ALOGD("Gestures: NEUTRAL"); +#endif + mPointerGesture.activeGestureId = -1; + mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; + mPointerGesture.currentGestureIdBits.clear(); + } + } else if (currentFingerCount == 1) { + // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) + // The pointer follows the active touch point. + // When in HOVER, emit HOVER_MOVE events at the pointer location. + // When in TAP_DRAG, emit MOVE events at the pointer location. + ALOG_ASSERT(activeTouchId >= 0); + + mPointerGesture.currentGestureMode = PointerGesture::HOVER; + if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { + if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { + float x, y; + mPointerController->getPosition(&x, &y); + if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && + fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { + mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; + } else { +#if DEBUG_GESTURES + ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", + x - mPointerGesture.tapX, y - mPointerGesture.tapY); +#endif + } + } else { +#if DEBUG_GESTURES + ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", + (when - mPointerGesture.tapUpTime) * 0.000001f); +#endif + } + } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { + mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; + } + + float deltaX = 0, deltaY = 0; + if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { + const RawPointerData::Pointer& currentPointer = + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); + const RawPointerData::Pointer& lastPointer = + mLastRawState.rawPointerData.pointerForId(activeTouchId); + deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; + deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + // Move the pointer using a relative motion. + // When using spots, the hover or drag will occur at the position of the anchor spot. + mPointerController->move(deltaX, deltaY); + } else { + mPointerVelocityControl.reset(); + } + + bool down; + if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { +#if DEBUG_GESTURES + ALOGD("Gestures: TAP_DRAG"); +#endif + down = true; + } else { +#if DEBUG_GESTURES + ALOGD("Gestures: HOVER"); +#endif + if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { + *outFinishPreviousGesture = true; + } + mPointerGesture.activeGestureId = 0; + down = false; + } + + float x, y; + mPointerController->getPosition(&x, &y); + + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, + down ? 1.0f : 0.0f); + + if (lastFingerCount == 0 && currentFingerCount != 0) { + mPointerGesture.resetTap(); + mPointerGesture.tapDownTime = when; + mPointerGesture.tapX = x; + mPointerGesture.tapY = y; + } + } else { + // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) + // We need to provide feedback for each finger that goes down so we cannot wait + // for the fingers to move before deciding what to do. + // + // The ambiguous case is deciding what to do when there are two fingers down but they + // have not moved enough to determine whether they are part of a drag or part of a + // freeform gesture, or just a press or long-press at the pointer location. + // + // When there are two fingers we start with the PRESS hypothesis and we generate a + // down at the pointer location. + // + // When the two fingers move enough or when additional fingers are added, we make + // a decision to transition into SWIPE or FREEFORM mode accordingly. + ALOG_ASSERT(activeTouchId >= 0); + + bool settled = when >= + mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval; + if (mPointerGesture.lastGestureMode != PointerGesture::PRESS && + mPointerGesture.lastGestureMode != PointerGesture::SWIPE && + mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { + *outFinishPreviousGesture = true; + } else if (!settled && currentFingerCount > lastFingerCount) { + // Additional pointers have gone down but not yet settled. + // Reset the gesture. +#if DEBUG_GESTURES + ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " + "settle time remaining %0.3fms", + (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval - + when) * 0.000001f); +#endif + *outCancelPreviousGesture = true; + } else { + // Continue previous gesture. + mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; + } + + if (*outFinishPreviousGesture || *outCancelPreviousGesture) { + mPointerGesture.currentGestureMode = PointerGesture::PRESS; + mPointerGesture.activeGestureId = 0; + mPointerGesture.referenceIdBits.clear(); + mPointerVelocityControl.reset(); + + // Use the centroid and pointer location as the reference points for the gesture. +#if DEBUG_GESTURES + ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " + "settle time remaining %0.3fms", + (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval - + when) * 0.000001f); +#endif + mCurrentRawState.rawPointerData + .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX, + &mPointerGesture.referenceTouchY); + mPointerController->getPosition(&mPointerGesture.referenceGestureX, + &mPointerGesture.referenceGestureY); + } + + // Clear the reference deltas for fingers not yet included in the reference calculation. + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value & + ~mPointerGesture.referenceIdBits.value); + !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + mPointerGesture.referenceDeltas[id].dx = 0; + mPointerGesture.referenceDeltas[id].dy = 0; + } + mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; + + // Add delta for all fingers and calculate a common movement delta. + float commonDeltaX = 0, commonDeltaY = 0; + BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value & + mCurrentCookedState.fingerIdBits.value); + for (BitSet32 idBits(commonIdBits); !idBits.isEmpty();) { + bool first = (idBits == commonIdBits); + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); + const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); + PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; + delta.dx += cpd.x - lpd.x; + delta.dy += cpd.y - lpd.y; + + if (first) { + commonDeltaX = delta.dx; + commonDeltaY = delta.dy; + } else { + commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); + commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); + } + } + + // Consider transitions from PRESS to SWIPE or MULTITOUCH. + if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { + float dist[MAX_POINTER_ID + 1]; + int32_t distOverThreshold = 0; + for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; + dist[id] = hypotf(delta.dx * mPointerXZoomScale, delta.dy * mPointerYZoomScale); + if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { + distOverThreshold += 1; + } + } + + // Only transition when at least two pointers have moved further than + // the minimum distance threshold. + if (distOverThreshold >= 2) { + if (currentFingerCount > 2) { + // There are more than two pointers, switch to FREEFORM. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", + currentFingerCount); +#endif + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } else { + // There are exactly two pointers. + BitSet32 idBits(mCurrentCookedState.fingerIdBits); + uint32_t id1 = idBits.clearFirstMarkedBit(); + uint32_t id2 = idBits.firstMarkedBit(); + const RawPointerData::Pointer& p1 = + mCurrentRawState.rawPointerData.pointerForId(id1); + const RawPointerData::Pointer& p2 = + mCurrentRawState.rawPointerData.pointerForId(id2); + float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); + if (mutualDistance > mPointerGestureMaxSwipeWidth) { + // There are two pointers but they are too far apart for a SWIPE, + // switch to FREEFORM. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", + mutualDistance, mPointerGestureMaxSwipeWidth); +#endif + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } else { + // There are two pointers. Wait for both pointers to start moving + // before deciding whether this is a SWIPE or FREEFORM gesture. + float dist1 = dist[id1]; + float dist2 = dist[id2]; + if (dist1 >= mConfig.pointerGestureMultitouchMinDistance && + dist2 >= mConfig.pointerGestureMultitouchMinDistance) { + // Calculate the dot product of the displacement vectors. + // When the vectors are oriented in approximately the same direction, + // the angle betweeen them is near zero and the cosine of the angle + // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * + // mag(v2). + PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; + PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; + float dx1 = delta1.dx * mPointerXZoomScale; + float dy1 = delta1.dy * mPointerYZoomScale; + float dx2 = delta2.dx * mPointerXZoomScale; + float dy2 = delta2.dy * mPointerYZoomScale; + float dot = dx1 * dx2 + dy1 * dy2; + float cosine = dot / (dist1 * dist2); // denominator always > 0 + if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { + // Pointers are moving in the same direction. Switch to SWIPE. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS transitioned to SWIPE, " + "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " + "cosine %0.3f >= %0.3f", + dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, + mConfig.pointerGestureMultitouchMinDistance, cosine, + mConfig.pointerGestureSwipeTransitionAngleCosine); +#endif + mPointerGesture.currentGestureMode = PointerGesture::SWIPE; + } else { + // Pointers are moving in different directions. Switch to FREEFORM. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS transitioned to FREEFORM, " + "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " + "cosine %0.3f < %0.3f", + dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, + mConfig.pointerGestureMultitouchMinDistance, cosine, + mConfig.pointerGestureSwipeTransitionAngleCosine); +#endif + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } + } + } + } + } + } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { + // Switch from SWIPE to FREEFORM if additional pointers go down. + // Cancel previous gesture. + if (currentFingerCount > 2) { +#if DEBUG_GESTURES + ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", + currentFingerCount); +#endif + *outCancelPreviousGesture = true; + mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; + } + } + + // Move the reference points based on the overall group motion of the fingers + // except in PRESS mode while waiting for a transition to occur. + if (mPointerGesture.currentGestureMode != PointerGesture::PRESS && + (commonDeltaX || commonDeltaY)) { + for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; + delta.dx = 0; + delta.dy = 0; + } + + mPointerGesture.referenceTouchX += commonDeltaX; + mPointerGesture.referenceTouchY += commonDeltaY; + + commonDeltaX *= mPointerXMovementScale; + commonDeltaY *= mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); + mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); + + mPointerGesture.referenceGestureX += commonDeltaX; + mPointerGesture.referenceGestureY += commonDeltaY; + } + + // Report gestures. + if (mPointerGesture.currentGestureMode == PointerGesture::PRESS || + mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { + // PRESS or SWIPE mode. +#if DEBUG_GESTURES + ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," + "activeGestureId=%d, currentTouchPointerCount=%d", + activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); +#endif + ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); + + mPointerGesture.currentGestureIdBits.clear(); + mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[0].clear(); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, + mPointerGesture.referenceGestureX); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, + mPointerGesture.referenceGestureY); + mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); + } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { + // FREEFORM mode. +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM activeTouchId=%d," + "activeGestureId=%d, currentTouchPointerCount=%d", + activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); +#endif + ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); + + mPointerGesture.currentGestureIdBits.clear(); + + BitSet32 mappedTouchIdBits; + BitSet32 usedGestureIdBits; + if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { + // Initially, assign the active gesture id to the active touch point + // if there is one. No other touch id bits are mapped yet. + if (!*outCancelPreviousGesture) { + mappedTouchIdBits.markBit(activeTouchId); + usedGestureIdBits.markBit(mPointerGesture.activeGestureId); + mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = + mPointerGesture.activeGestureId; + } else { + mPointerGesture.activeGestureId = -1; + } + } else { + // Otherwise, assume we mapped all touches from the previous frame. + // Reuse all mappings that are still applicable. + mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value & + mCurrentCookedState.fingerIdBits.value; + usedGestureIdBits = mPointerGesture.lastGestureIdBits; + + // Check whether we need to choose a new active gesture id because the + // current went went up. + for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value & + ~mCurrentCookedState.fingerIdBits.value); + !upTouchIdBits.isEmpty();) { + uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); + uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; + if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { + mPointerGesture.activeGestureId = -1; + break; + } + } + } + +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM follow up " + "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " + "activeGestureId=%d", + mappedTouchIdBits.value, usedGestureIdBits.value, + mPointerGesture.activeGestureId); +#endif + + BitSet32 idBits(mCurrentCookedState.fingerIdBits); + for (uint32_t i = 0; i < currentFingerCount; i++) { + uint32_t touchId = idBits.clearFirstMarkedBit(); + uint32_t gestureId; + if (!mappedTouchIdBits.hasBit(touchId)) { + gestureId = usedGestureIdBits.markFirstUnmarkedBit(); + mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM " + "new mapping for touch id %d -> gesture id %d", + touchId, gestureId); +#endif + } else { + gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM " + "existing mapping for touch id %d -> gesture id %d", + touchId, gestureId); +#endif + } + mPointerGesture.currentGestureIdBits.markBit(gestureId); + mPointerGesture.currentGestureIdToIndex[gestureId] = i; + + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(touchId); + float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; + float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale; + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + + mPointerGesture.currentGestureProperties[i].clear(); + mPointerGesture.currentGestureProperties[i].id = gestureId; + mPointerGesture.currentGestureProperties[i].toolType = + AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureCoords[i].clear(); + mPointerGesture.currentGestureCoords[i] + .setAxisValue(AMOTION_EVENT_AXIS_X, + mPointerGesture.referenceGestureX + deltaX); + mPointerGesture.currentGestureCoords[i] + .setAxisValue(AMOTION_EVENT_AXIS_Y, + mPointerGesture.referenceGestureY + deltaY); + mPointerGesture.currentGestureCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, + 1.0f); + } + + if (mPointerGesture.activeGestureId < 0) { + mPointerGesture.activeGestureId = + mPointerGesture.currentGestureIdBits.firstMarkedBit(); +#if DEBUG_GESTURES + ALOGD("Gestures: FREEFORM new " + "activeGestureId=%d", + mPointerGesture.activeGestureId); +#endif + } + } + } + + mPointerController->setButtonState(mCurrentRawState.buttonState); + +#if DEBUG_GESTURES + ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " + "currentGestureMode=%d, currentGestureIdBits=0x%08x, " + "lastGestureMode=%d, lastGestureIdBits=0x%08x", + toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), + mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value, + mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value); + for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; + const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; + ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " + "x=%0.3f, y=%0.3f, pressure=%0.3f", + id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_Y), + coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); + } + for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; + const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; + const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; + ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " + "x=%0.3f, y=%0.3f, pressure=%0.3f", + id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), + coords.getAxisValue(AMOTION_EVENT_AXIS_Y), + coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); + } +#endif + return true; +} + +void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + bool down, hovering; + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); + uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; + float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); + float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); + mPointerController->setPosition(x, y); + + hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); + down = !hovering; + + mPointerController->getPosition(&x, &y); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedState.cookedPointerData.pointerCoords[index]); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerSimple.currentProperties.id = 0; + mPointerSimple.currentProperties.toolType = + mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; + } else { + down = false; + hovering = false; + } + + dispatchPointerSimple(when, policyFlags, down, hovering); +} + +void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { + abortPointerSimple(when, policyFlags); +} + +void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + bool down, hovering; + if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); + uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + float deltaX = 0, deltaY = 0; + if (mLastCookedState.mouseIdBits.hasBit(id)) { + uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x - + mLastRawState.rawPointerData.pointers[lastIndex].x) * + mPointerXMovementScale; + deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y - + mLastRawState.rawPointerData.pointers[lastIndex].y) * + mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + mPointerController->move(deltaX, deltaY); + } else { + mPointerVelocityControl.reset(); + } + + down = isPointerDown(mCurrentRawState.buttonState); + hovering = !down; + + float x, y; + mPointerController->getPosition(&x, &y); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, + hovering ? 0.0f : 1.0f); + mPointerSimple.currentProperties.id = 0; + mPointerSimple.currentProperties.toolType = + mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; + } else { + mPointerVelocityControl.reset(); + + down = false; + hovering = false; + } + + dispatchPointerSimple(when, policyFlags, down, hovering); +} + +void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { + abortPointerSimple(when, policyFlags); + + mPointerVelocityControl.reset(); +} + +void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, + bool hovering) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t displayId = mViewport.displayId; + + if (mPointerController != nullptr) { + if (down || hovering) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + mPointerController->clearSpots(); + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } + displayId = mPointerController->getDisplayId(); + } + + if (mPointerSimple.down && !down) { + mPointerSimple.down = false; + + // Send up. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, + mLastRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + if (mPointerSimple.hovering && !hovering) { + mPointerSimple.hovering = false; + + // Send hover exit. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, + metaState, mLastRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + if (down) { + if (!mPointerSimple.down) { + mPointerSimple.down = true; + mPointerSimple.downTime = when; + + // Send down. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, + metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, + &mPointerSimple.currentCoords, mOrientedXPrecision, + mOrientedYPrecision, mPointerSimple.downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + // Send move. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + if (hovering) { + if (!mPointerSimple.hovering) { + mPointerSimple.hovering = true; + + // Send hover enter. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, + metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, + &mPointerSimple.currentCoords, mOrientedXPrecision, + mOrientedYPrecision, mPointerSimple.downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + // Send hover move. + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { + float vscroll = mCurrentRawState.rawVScroll; + float hscroll = mCurrentRawState.rawHScroll; + mWheelYVelocityControl.move(when, nullptr, &vscroll); + mWheelXVelocityControl.move(when, &hscroll, nullptr); + + // Send scroll. + PointerCoords pointerCoords; + pointerCoords.copyFrom(mPointerSimple.currentCoords); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); + + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &pointerCoords, + mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime, + /* videoFrames */ {}); + getListener()->notifyMotion(&args); + } + + // Save state. + if (down || hovering) { + mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); + mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); + } else { + mPointerSimple.reset(); + } +} + +void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + dispatchPointerSimple(when, policyFlags, false, false); +} + +void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, + int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, + uint32_t deviceTimestamp, const PointerProperties* properties, + const PointerCoords* coords, const uint32_t* idToIndex, + BitSet32 idBits, int32_t changedId, float xPrecision, + float yPrecision, nsecs_t downTime) { + PointerCoords pointerCoords[MAX_POINTERS]; + PointerProperties pointerProperties[MAX_POINTERS]; + uint32_t pointerCount = 0; + while (!idBits.isEmpty()) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t index = idToIndex[id]; + pointerProperties[pointerCount].copyFrom(properties[index]); + pointerCoords[pointerCount].copyFrom(coords[index]); + + if (changedId >= 0 && id == uint32_t(changedId)) { + action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + } + + pointerCount += 1; + } + + ALOG_ASSERT(pointerCount != 0); + + if (changedId >= 0 && pointerCount == 1) { + // Replace initial down and final up action. + // We can compare the action without masking off the changed pointer index + // because we know the index is 0. + if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { + action = AMOTION_EVENT_ACTION_DOWN; + } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { + action = AMOTION_EVENT_ACTION_UP; + } else { + // Can't happen. + ALOG_ASSERT(false); + } + } + const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE); + const int32_t deviceId = getDeviceId(); + std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId); + std::for_each(frames.begin(), frames.end(), + [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, source, displayId, + policyFlags, action, actionButton, flags, metaState, buttonState, + MotionClassification::NONE, edgeFlags, deviceTimestamp, pointerCount, + pointerProperties, pointerCoords, xPrecision, yPrecision, downTime, + std::move(frames)); + getListener()->notifyMotion(&args); +} + +bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, + const PointerCoords* inCoords, + const uint32_t* inIdToIndex, + PointerProperties* outProperties, + PointerCoords* outCoords, const uint32_t* outIdToIndex, + BitSet32 idBits) const { + bool changed = false; + while (!idBits.isEmpty()) { + uint32_t id = idBits.clearFirstMarkedBit(); + uint32_t inIndex = inIdToIndex[id]; + uint32_t outIndex = outIdToIndex[id]; + + const PointerProperties& curInProperties = inProperties[inIndex]; + const PointerCoords& curInCoords = inCoords[inIndex]; + PointerProperties& curOutProperties = outProperties[outIndex]; + PointerCoords& curOutCoords = outCoords[outIndex]; + + if (curInProperties != curOutProperties) { + curOutProperties.copyFrom(curInProperties); + changed = true; + } + + if (curInCoords != curOutCoords) { + curOutCoords.copyFrom(curInCoords); + changed = true; + } + } + return changed; +} + +void TouchInputMapper::fadePointer() { + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } +} + +void TouchInputMapper::cancelTouch(nsecs_t when) { + abortPointerUsage(when, 0 /*policyFlags*/); + abortTouches(when, 0 /* policyFlags*/); +} + +bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { + const float scaledX = x * mXScale; + const float scaledY = y * mYScale; + return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && + scaledX >= mPhysicalLeft && scaledX <= mPhysicalLeft + mPhysicalWidth && + y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue && + scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight; +} + +const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) { + for (const VirtualKey& virtualKey : mVirtualKeys) { +#if DEBUG_VIRTUAL_KEYS + ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " + "left=%d, top=%d, right=%d, bottom=%d", + x, y, virtualKey.keyCode, virtualKey.scanCode, virtualKey.hitLeft, virtualKey.hitTop, + virtualKey.hitRight, virtualKey.hitBottom); +#endif + + if (virtualKey.isHit(x, y)) { + return &virtualKey; + } + } + + return nullptr; +} + +void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { + uint32_t currentPointerCount = current->rawPointerData.pointerCount; + uint32_t lastPointerCount = last->rawPointerData.pointerCount; + + current->rawPointerData.clearIdBits(); + + if (currentPointerCount == 0) { + // No pointers to assign. + return; + } + + if (lastPointerCount == 0) { + // All pointers are new. + for (uint32_t i = 0; i < currentPointerCount; i++) { + uint32_t id = i; + current->rawPointerData.pointers[i].id = id; + current->rawPointerData.idToIndex[id] = i; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); + } + return; + } + + if (currentPointerCount == 1 && lastPointerCount == 1 && + current->rawPointerData.pointers[0].toolType == last->rawPointerData.pointers[0].toolType) { + // Only one pointer and no change in count so it must have the same id as before. + uint32_t id = last->rawPointerData.pointers[0].id; + current->rawPointerData.pointers[0].id = id; + current->rawPointerData.idToIndex[id] = 0; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); + return; + } + + // General case. + // We build a heap of squared euclidean distances between current and last pointers + // associated with the current and last pointer indices. Then, we find the best + // match (by distance) for each current pointer. + // The pointers must have the same tool type but it is possible for them to + // transition from hovering to touching or vice-versa while retaining the same id. + PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; + + uint32_t heapSize = 0; + for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; + currentPointerIndex++) { + for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; + lastPointerIndex++) { + const RawPointerData::Pointer& currentPointer = + current->rawPointerData.pointers[currentPointerIndex]; + const RawPointerData::Pointer& lastPointer = + last->rawPointerData.pointers[lastPointerIndex]; + if (currentPointer.toolType == lastPointer.toolType) { + int64_t deltaX = currentPointer.x - lastPointer.x; + int64_t deltaY = currentPointer.y - lastPointer.y; + + uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); + + // Insert new element into the heap (sift up). + heap[heapSize].currentPointerIndex = currentPointerIndex; + heap[heapSize].lastPointerIndex = lastPointerIndex; + heap[heapSize].distance = distance; + heapSize += 1; + } + } + } + + // Heapify + for (uint32_t startIndex = heapSize / 2; startIndex != 0;) { + startIndex -= 1; + for (uint32_t parentIndex = startIndex;;) { + uint32_t childIndex = parentIndex * 2 + 1; + if (childIndex >= heapSize) { + break; + } + + if (childIndex + 1 < heapSize && + heap[childIndex + 1].distance < heap[childIndex].distance) { + childIndex += 1; + } + + if (heap[parentIndex].distance <= heap[childIndex].distance) { + break; + } + + swap(heap[parentIndex], heap[childIndex]); + parentIndex = childIndex; + } + } + +#if DEBUG_POINTER_ASSIGNMENT + ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); + for (size_t i = 0; i < heapSize; i++) { + ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i, + heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); + } +#endif + + // Pull matches out by increasing order of distance. + // To avoid reassigning pointers that have already been matched, the loop keeps track + // of which last and current pointers have been matched using the matchedXXXBits variables. + // It also tracks the used pointer id bits. + BitSet32 matchedLastBits(0); + BitSet32 matchedCurrentBits(0); + BitSet32 usedIdBits(0); + bool first = true; + for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { + while (heapSize > 0) { + if (first) { + // The first time through the loop, we just consume the root element of + // the heap (the one with smallest distance). + first = false; + } else { + // Previous iterations consumed the root element of the heap. + // Pop root element off of the heap (sift down). + heap[0] = heap[heapSize]; + for (uint32_t parentIndex = 0;;) { + uint32_t childIndex = parentIndex * 2 + 1; + if (childIndex >= heapSize) { + break; + } + + if (childIndex + 1 < heapSize && + heap[childIndex + 1].distance < heap[childIndex].distance) { + childIndex += 1; + } + + if (heap[parentIndex].distance <= heap[childIndex].distance) { + break; + } + + swap(heap[parentIndex], heap[childIndex]); + parentIndex = childIndex; + } + +#if DEBUG_POINTER_ASSIGNMENT + ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); + for (size_t i = 0; i < heapSize; i++) { + ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i, + heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); + } +#endif + } + + heapSize -= 1; + + uint32_t currentPointerIndex = heap[0].currentPointerIndex; + if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched + + uint32_t lastPointerIndex = heap[0].lastPointerIndex; + if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched + + matchedCurrentBits.markBit(currentPointerIndex); + matchedLastBits.markBit(lastPointerIndex); + + uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering( + currentPointerIndex)); + usedIdBits.markBit(id); + +#if DEBUG_POINTER_ASSIGNMENT + ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 ", id=%" PRIu32 + ", distance=%" PRIu64, + lastPointerIndex, currentPointerIndex, id, heap[0].distance); +#endif + break; + } + } + + // Assign fresh ids to pointers that were not matched in the process. + for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { + uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); + uint32_t id = usedIdBits.markFirstUnmarkedBit(); + + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); + +#if DEBUG_POINTER_ASSIGNMENT + ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id); +#endif + } +} + +int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { + return AKEY_STATE_VIRTUAL; + } + + for (const VirtualKey& virtualKey : mVirtualKeys) { + if (virtualKey.keyCode == keyCode) { + return AKEY_STATE_UP; + } + } + + return AKEY_STATE_UNKNOWN; +} + +int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { + return AKEY_STATE_VIRTUAL; + } + + for (const VirtualKey& virtualKey : mVirtualKeys) { + if (virtualKey.scanCode == scanCode) { + return AKEY_STATE_UP; + } + } + + return AKEY_STATE_UNKNOWN; +} + +bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) { + for (const VirtualKey& virtualKey : mVirtualKeys) { + for (size_t i = 0; i < numCodes; i++) { + if (virtualKey.keyCode == keyCodes[i]) { + outFlags[i] = 1; + } + } + } + + return true; +} + +std::optional<int32_t> TouchInputMapper::getAssociatedDisplay() { + if (mParameters.hasAssociatedDisplay) { + if (mDeviceMode == DEVICE_MODE_POINTER) { + return std::make_optional(mPointerController->getDisplayId()); + } else { + return std::make_optional(mViewport.displayId); + } + } + return std::nullopt; +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h new file mode 100644 index 0000000000..d14812aecd --- /dev/null +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -0,0 +1,838 @@ +/* + * 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_INPUTREADER_TOUCH_INPUT_MAPPER_H +#define _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H + +#include "CursorButtonAccumulator.h" +#include "CursorScrollAccumulator.h" +#include "EventHub.h" +#include "InputMapper.h" +#include "InputReaderBase.h" +#include "TouchButtonAccumulator.h" + +#include <stdint.h> + +namespace android { + +/** + * Basic statistics information. + * Keep track of min, max, average, and standard deviation of the received samples. + * Used to report latency information about input events. + */ +struct LatencyStatistics { + float min; + float max; + // Sum of all samples + float sum; + // Sum of squares of all samples + float sum2; + // The number of samples + size_t count; + // The last time statistics were reported. + nsecs_t lastReportTime; + + LatencyStatistics() { reset(systemTime(SYSTEM_TIME_MONOTONIC)); } + + inline void addValue(float x) { + if (x < min) { + min = x; + } + if (x > max) { + max = x; + } + sum += x; + sum2 += x * x; + count++; + } + + // Get the average value. Should not be called if no samples have been added. + inline float mean() { + if (count == 0) { + return 0; + } + return sum / count; + } + + // Get the standard deviation. Should not be called if no samples have been added. + inline float stdev() { + if (count == 0) { + return 0; + } + float average = mean(); + return sqrt(sum2 / count - average * average); + } + + /** + * Reset internal state. The variable 'when' is the time when the data collection started. + * Call this to start a new data collection window. + */ + inline void reset(nsecs_t when) { + max = 0; + min = std::numeric_limits<float>::max(); + sum = 0; + sum2 = 0; + count = 0; + lastReportTime = when; + } +}; + +/* Raw axis information from the driver. */ +struct RawPointerAxes { + RawAbsoluteAxisInfo x; + RawAbsoluteAxisInfo y; + RawAbsoluteAxisInfo pressure; + RawAbsoluteAxisInfo touchMajor; + RawAbsoluteAxisInfo touchMinor; + RawAbsoluteAxisInfo toolMajor; + RawAbsoluteAxisInfo toolMinor; + RawAbsoluteAxisInfo orientation; + RawAbsoluteAxisInfo distance; + RawAbsoluteAxisInfo tiltX; + RawAbsoluteAxisInfo tiltY; + RawAbsoluteAxisInfo trackingId; + RawAbsoluteAxisInfo slot; + + RawPointerAxes(); + inline int32_t getRawWidth() const { return x.maxValue - x.minValue + 1; } + inline int32_t getRawHeight() const { return y.maxValue - y.minValue + 1; } + void clear(); +}; + +/* Raw data for a collection of pointers including a pointer id mapping table. */ +struct RawPointerData { + struct Pointer { + uint32_t id; + int32_t x; + int32_t y; + int32_t pressure; + int32_t touchMajor; + int32_t touchMinor; + int32_t toolMajor; + int32_t toolMinor; + int32_t orientation; + int32_t distance; + int32_t tiltX; + int32_t tiltY; + int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant + bool isHovering; + }; + + uint32_t pointerCount; + Pointer pointers[MAX_POINTERS]; + BitSet32 hoveringIdBits, touchingIdBits; + uint32_t idToIndex[MAX_POINTER_ID + 1]; + + RawPointerData(); + void clear(); + void copyFrom(const RawPointerData& other); + void getCentroidOfTouchingPointers(float* outX, float* outY) const; + + inline void markIdBit(uint32_t id, bool isHovering) { + if (isHovering) { + hoveringIdBits.markBit(id); + } else { + touchingIdBits.markBit(id); + } + } + + inline void clearIdBits() { + hoveringIdBits.clear(); + touchingIdBits.clear(); + } + + inline const Pointer& pointerForId(uint32_t id) const { return pointers[idToIndex[id]]; } + + inline bool isHovering(uint32_t pointerIndex) { return pointers[pointerIndex].isHovering; } +}; + +/* Cooked data for a collection of pointers including a pointer id mapping table. */ +struct CookedPointerData { + uint32_t pointerCount; + PointerProperties pointerProperties[MAX_POINTERS]; + PointerCoords pointerCoords[MAX_POINTERS]; + BitSet32 hoveringIdBits, touchingIdBits; + uint32_t idToIndex[MAX_POINTER_ID + 1]; + + CookedPointerData(); + void clear(); + void copyFrom(const CookedPointerData& other); + + inline const PointerCoords& pointerCoordsForId(uint32_t id) const { + return pointerCoords[idToIndex[id]]; + } + + inline PointerCoords& editPointerCoordsWithId(uint32_t id) { + return pointerCoords[idToIndex[id]]; + } + + inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { + return pointerProperties[idToIndex[id]]; + } + + inline bool isHovering(uint32_t pointerIndex) const { + return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); + } + + inline bool isTouching(uint32_t pointerIndex) const { + return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); + } +}; + +class TouchInputMapper : public InputMapper { +public: + explicit TouchInputMapper(InputDevice* device); + virtual ~TouchInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(std::string& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + + virtual void fadePointer(); + virtual void cancelTouch(nsecs_t when); + virtual void timeoutExpired(nsecs_t when); + virtual void updateExternalStylusState(const StylusState& state); + virtual std::optional<int32_t> getAssociatedDisplay(); + +protected: + CursorButtonAccumulator mCursorButtonAccumulator; + CursorScrollAccumulator mCursorScrollAccumulator; + TouchButtonAccumulator mTouchButtonAccumulator; + + struct VirtualKey { + int32_t keyCode; + int32_t scanCode; + uint32_t flags; + + // computed hit box, specified in touch screen coords based on known display size + int32_t hitLeft; + int32_t hitTop; + int32_t hitRight; + int32_t hitBottom; + + inline bool isHit(int32_t x, int32_t y) const { + return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; + } + }; + + // Input sources and device mode. + uint32_t mSource; + + enum DeviceMode { + DEVICE_MODE_DISABLED, // input is disabled + DEVICE_MODE_DIRECT, // direct mapping (touchscreen) + DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) + DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation) + DEVICE_MODE_POINTER, // pointer mapping (pointer) + }; + DeviceMode mDeviceMode; + + // The reader's configuration. + InputReaderConfiguration mConfig; + + // Immutable configuration parameters. + struct Parameters { + enum DeviceType { + DEVICE_TYPE_TOUCH_SCREEN, + DEVICE_TYPE_TOUCH_PAD, + DEVICE_TYPE_TOUCH_NAVIGATION, + DEVICE_TYPE_POINTER, + }; + + DeviceType deviceType; + bool hasAssociatedDisplay; + bool associatedDisplayIsExternal; + bool orientationAware; + bool hasButtonUnderPad; + std::string uniqueDisplayId; + + enum GestureMode { + GESTURE_MODE_SINGLE_TOUCH, + GESTURE_MODE_MULTI_TOUCH, + }; + GestureMode gestureMode; + + bool wake; + } mParameters; + + // Immutable calibration parameters in parsed form. + struct Calibration { + // Size + enum SizeCalibration { + SIZE_CALIBRATION_DEFAULT, + SIZE_CALIBRATION_NONE, + SIZE_CALIBRATION_GEOMETRIC, + SIZE_CALIBRATION_DIAMETER, + SIZE_CALIBRATION_BOX, + SIZE_CALIBRATION_AREA, + }; + + SizeCalibration sizeCalibration; + + bool haveSizeScale; + float sizeScale; + bool haveSizeBias; + float sizeBias; + bool haveSizeIsSummed; + bool sizeIsSummed; + + // Pressure + enum PressureCalibration { + PRESSURE_CALIBRATION_DEFAULT, + PRESSURE_CALIBRATION_NONE, + PRESSURE_CALIBRATION_PHYSICAL, + PRESSURE_CALIBRATION_AMPLITUDE, + }; + + PressureCalibration pressureCalibration; + bool havePressureScale; + float pressureScale; + + // Orientation + enum OrientationCalibration { + ORIENTATION_CALIBRATION_DEFAULT, + ORIENTATION_CALIBRATION_NONE, + ORIENTATION_CALIBRATION_INTERPOLATED, + ORIENTATION_CALIBRATION_VECTOR, + }; + + OrientationCalibration orientationCalibration; + + // Distance + enum DistanceCalibration { + DISTANCE_CALIBRATION_DEFAULT, + DISTANCE_CALIBRATION_NONE, + DISTANCE_CALIBRATION_SCALED, + }; + + DistanceCalibration distanceCalibration; + bool haveDistanceScale; + float distanceScale; + + enum CoverageCalibration { + COVERAGE_CALIBRATION_DEFAULT, + COVERAGE_CALIBRATION_NONE, + COVERAGE_CALIBRATION_BOX, + }; + + CoverageCalibration coverageCalibration; + + inline void applySizeScaleAndBias(float* outSize) const { + if (haveSizeScale) { + *outSize *= sizeScale; + } + if (haveSizeBias) { + *outSize += sizeBias; + } + if (*outSize < 0) { + *outSize = 0; + } + } + } mCalibration; + + // Affine location transformation/calibration + struct TouchAffineTransformation mAffineTransform; + + RawPointerAxes mRawPointerAxes; + + struct RawState { + nsecs_t when; + uint32_t deviceTimestamp; + + // Raw pointer sample data. + RawPointerData rawPointerData; + + int32_t buttonState; + + // Scroll state. + int32_t rawVScroll; + int32_t rawHScroll; + + void copyFrom(const RawState& other) { + when = other.when; + deviceTimestamp = other.deviceTimestamp; + rawPointerData.copyFrom(other.rawPointerData); + buttonState = other.buttonState; + rawVScroll = other.rawVScroll; + rawHScroll = other.rawHScroll; + } + + void clear() { + when = 0; + deviceTimestamp = 0; + rawPointerData.clear(); + buttonState = 0; + rawVScroll = 0; + rawHScroll = 0; + } + }; + + struct CookedState { + uint32_t deviceTimestamp; + // Cooked pointer sample data. + CookedPointerData cookedPointerData; + + // Id bits used to differentiate fingers, stylus and mouse tools. + BitSet32 fingerIdBits; + BitSet32 stylusIdBits; + BitSet32 mouseIdBits; + + int32_t buttonState; + + void copyFrom(const CookedState& other) { + deviceTimestamp = other.deviceTimestamp; + cookedPointerData.copyFrom(other.cookedPointerData); + fingerIdBits = other.fingerIdBits; + stylusIdBits = other.stylusIdBits; + mouseIdBits = other.mouseIdBits; + buttonState = other.buttonState; + } + + void clear() { + deviceTimestamp = 0; + cookedPointerData.clear(); + fingerIdBits.clear(); + stylusIdBits.clear(); + mouseIdBits.clear(); + buttonState = 0; + } + }; + + std::vector<RawState> mRawStatesPending; + RawState mCurrentRawState; + CookedState mCurrentCookedState; + RawState mLastRawState; + CookedState mLastCookedState; + + // State provided by an external stylus + StylusState mExternalStylusState; + int64_t mExternalStylusId; + nsecs_t mExternalStylusFusionTimeout; + bool mExternalStylusDataPending; + + // True if we sent a HOVER_ENTER event. + bool mSentHoverEnter; + + // Have we assigned pointer IDs for this stream + bool mHavePointerIds; + + // Is the current stream of direct touch events aborted + bool mCurrentMotionAborted; + + // The time the primary pointer last went down. + nsecs_t mDownTime; + + // The pointer controller, or null if the device is not a pointer. + sp<PointerControllerInterface> mPointerController; + + std::vector<VirtualKey> mVirtualKeys; + + virtual void configureParameters(); + virtual void dumpParameters(std::string& dump); + virtual void configureRawPointerAxes(); + virtual void dumpRawPointerAxes(std::string& dump); + virtual void configureSurface(nsecs_t when, bool* outResetNeeded); + virtual void dumpSurface(std::string& dump); + virtual void configureVirtualKeys(); + virtual void dumpVirtualKeys(std::string& dump); + virtual void parseCalibration(); + virtual void resolveCalibration(); + virtual void dumpCalibration(std::string& dump); + virtual void updateAffineTransformation(); + virtual void dumpAffineTransformation(std::string& dump); + virtual void resolveExternalStylusPresence(); + virtual bool hasStylus() const = 0; + virtual bool hasExternalStylus() const; + + virtual void syncTouch(nsecs_t when, RawState* outState) = 0; + +private: + // The current viewport. + // The components of the viewport are specified in the display's rotated orientation. + DisplayViewport mViewport; + + // The surface orientation, width and height set by configureSurface(). + // The width and height are derived from the viewport but are specified + // in the natural orientation. + // The surface origin specifies how the surface coordinates should be translated + // to align with the logical display coordinate space. + int32_t mSurfaceWidth; + int32_t mSurfaceHeight; + int32_t mSurfaceLeft; + int32_t mSurfaceTop; + + // Similar to the surface coordinates, but in the raw display coordinate space rather than in + // the logical coordinate space. + int32_t mPhysicalWidth; + int32_t mPhysicalHeight; + int32_t mPhysicalLeft; + int32_t mPhysicalTop; + + // The orientation may be different from the viewport orientation as it specifies + // the rotation of the surface coordinates required to produce the viewport's + // requested orientation, so it will depend on whether the device is orientation aware. + int32_t mSurfaceOrientation; + + // Translation and scaling factors, orientation-independent. + float mXTranslate; + float mXScale; + float mXPrecision; + + float mYTranslate; + float mYScale; + float mYPrecision; + + float mGeometricScale; + + float mPressureScale; + + float mSizeScale; + + float mOrientationScale; + + float mDistanceScale; + + bool mHaveTilt; + float mTiltXCenter; + float mTiltXScale; + float mTiltYCenter; + float mTiltYScale; + + bool mExternalStylusConnected; + + // Oriented motion ranges for input device info. + struct OrientedRanges { + InputDeviceInfo::MotionRange x; + InputDeviceInfo::MotionRange y; + InputDeviceInfo::MotionRange pressure; + + bool haveSize; + InputDeviceInfo::MotionRange size; + + bool haveTouchSize; + InputDeviceInfo::MotionRange touchMajor; + InputDeviceInfo::MotionRange touchMinor; + + bool haveToolSize; + InputDeviceInfo::MotionRange toolMajor; + InputDeviceInfo::MotionRange toolMinor; + + bool haveOrientation; + InputDeviceInfo::MotionRange orientation; + + bool haveDistance; + InputDeviceInfo::MotionRange distance; + + bool haveTilt; + InputDeviceInfo::MotionRange tilt; + + OrientedRanges() { clear(); } + + void clear() { + haveSize = false; + haveTouchSize = false; + haveToolSize = false; + haveOrientation = false; + haveDistance = false; + haveTilt = false; + } + } mOrientedRanges; + + // Oriented dimensions and precision. + float mOrientedXPrecision; + float mOrientedYPrecision; + + struct CurrentVirtualKeyState { + bool down; + bool ignored; + nsecs_t downTime; + int32_t keyCode; + int32_t scanCode; + } mCurrentVirtualKey; + + // Scale factor for gesture or mouse based pointer movements. + float mPointerXMovementScale; + float mPointerYMovementScale; + + // Scale factor for gesture based zooming and other freeform motions. + float mPointerXZoomScale; + float mPointerYZoomScale; + + // The maximum swipe width. + float mPointerGestureMaxSwipeWidth; + + struct PointerDistanceHeapElement { + uint32_t currentPointerIndex : 8; + uint32_t lastPointerIndex : 8; + uint64_t distance : 48; // squared distance + }; + + enum PointerUsage { + POINTER_USAGE_NONE, + POINTER_USAGE_GESTURES, + POINTER_USAGE_STYLUS, + POINTER_USAGE_MOUSE, + }; + PointerUsage mPointerUsage; + + struct PointerGesture { + enum Mode { + // No fingers, button is not pressed. + // Nothing happening. + NEUTRAL, + + // No fingers, button is not pressed. + // Tap detected. + // Emits DOWN and UP events at the pointer location. + TAP, + + // Exactly one finger dragging following a tap. + // Pointer follows the active finger. + // Emits DOWN, MOVE and UP events at the pointer location. + // + // Detect double-taps when the finger goes up while in TAP_DRAG mode. + TAP_DRAG, + + // Button is pressed. + // Pointer follows the active finger if there is one. Other fingers are ignored. + // Emits DOWN, MOVE and UP events at the pointer location. + BUTTON_CLICK_OR_DRAG, + + // Exactly one finger, button is not pressed. + // Pointer follows the active finger. + // Emits HOVER_MOVE events at the pointer location. + // + // Detect taps when the finger goes up while in HOVER mode. + HOVER, + + // Exactly two fingers but neither have moved enough to clearly indicate + // whether a swipe or freeform gesture was intended. We consider the + // pointer to be pressed so this enables clicking or long-pressing on buttons. + // Pointer does not move. + // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. + PRESS, + + // Exactly two fingers moving in the same direction, button is not pressed. + // Pointer does not move. + // Emits DOWN, MOVE and UP events with a single pointer coordinate that + // follows the midpoint between both fingers. + SWIPE, + + // Two or more fingers moving in arbitrary directions, button is not pressed. + // Pointer does not move. + // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow + // each finger individually relative to the initial centroid of the finger. + FREEFORM, + + // Waiting for quiet time to end before starting the next gesture. + QUIET, + }; + + // Time the first finger went down. + nsecs_t firstTouchTime; + + // The active pointer id from the raw touch data. + int32_t activeTouchId; // -1 if none + + // The active pointer id from the gesture last delivered to the application. + int32_t activeGestureId; // -1 if none + + // Pointer coords and ids for the current and previous pointer gesture. + Mode currentGestureMode; + BitSet32 currentGestureIdBits; + uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; + PointerProperties currentGestureProperties[MAX_POINTERS]; + PointerCoords currentGestureCoords[MAX_POINTERS]; + + Mode lastGestureMode; + BitSet32 lastGestureIdBits; + uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; + PointerProperties lastGestureProperties[MAX_POINTERS]; + PointerCoords lastGestureCoords[MAX_POINTERS]; + + // Time the pointer gesture last went down. + nsecs_t downTime; + + // Time when the pointer went down for a TAP. + nsecs_t tapDownTime; + + // Time when the pointer went up for a TAP. + nsecs_t tapUpTime; + + // Location of initial tap. + float tapX, tapY; + + // Time we started waiting for quiescence. + nsecs_t quietTime; + + // Reference points for multitouch gestures. + float referenceTouchX; // reference touch X/Y coordinates in surface units + float referenceTouchY; + float referenceGestureX; // reference gesture X/Y coordinates in pixels + float referenceGestureY; + + // Distance that each pointer has traveled which has not yet been + // subsumed into the reference gesture position. + BitSet32 referenceIdBits; + struct Delta { + float dx, dy; + }; + Delta referenceDeltas[MAX_POINTER_ID + 1]; + + // Describes how touch ids are mapped to gesture ids for freeform gestures. + uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; + + // A velocity tracker for determining whether to switch active pointers during drags. + VelocityTracker velocityTracker; + + void reset() { + firstTouchTime = LLONG_MIN; + activeTouchId = -1; + activeGestureId = -1; + currentGestureMode = NEUTRAL; + currentGestureIdBits.clear(); + lastGestureMode = NEUTRAL; + lastGestureIdBits.clear(); + downTime = 0; + velocityTracker.clear(); + resetTap(); + resetQuietTime(); + } + + void resetTap() { + tapDownTime = LLONG_MIN; + tapUpTime = LLONG_MIN; + } + + void resetQuietTime() { quietTime = LLONG_MIN; } + } mPointerGesture; + + struct PointerSimple { + PointerCoords currentCoords; + PointerProperties currentProperties; + PointerCoords lastCoords; + PointerProperties lastProperties; + + // True if the pointer is down. + bool down; + + // True if the pointer is hovering. + bool hovering; + + // Time the pointer last went down. + nsecs_t downTime; + + void reset() { + currentCoords.clear(); + currentProperties.clear(); + lastCoords.clear(); + lastProperties.clear(); + down = false; + hovering = false; + downTime = 0; + } + } mPointerSimple; + + // The pointer and scroll velocity controls. + VelocityControl mPointerVelocityControl; + VelocityControl mWheelXVelocityControl; + VelocityControl mWheelYVelocityControl; + + // Latency statistics for touch events + struct LatencyStatistics mStatistics; + + std::optional<DisplayViewport> findViewport(); + + void resetExternalStylus(); + void clearStylusDataPendingFlags(); + + void sync(nsecs_t when); + + bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); + void processRawTouches(bool timeout); + void cookAndDispatch(nsecs_t when); + void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, + int32_t keyEventFlags); + + void dispatchTouches(nsecs_t when, uint32_t policyFlags); + void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); + void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); + void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags); + void dispatchButtonPress(nsecs_t when, uint32_t policyFlags); + const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData); + void cookPointerData(); + void abortTouches(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); + void abortPointerUsage(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); + void abortPointerGestures(nsecs_t when, uint32_t policyFlags); + bool preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, + bool* outFinishPreviousGesture, bool isTimeout); + + void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); + void abortPointerStylus(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); + void abortPointerMouse(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, bool hovering); + void abortPointerSimple(nsecs_t when, uint32_t policyFlags); + + bool assignExternalStylusId(const RawState& state, bool timeout); + void applyExternalStylusButtonState(nsecs_t when); + void applyExternalStylusTouchState(nsecs_t when); + + // Dispatches a motion event. + // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the + // method will take care of setting the index and transmuting the action to DOWN or UP + // it is the first / last pointer to go down / up. + void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, + int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, + int32_t edgeFlags, uint32_t deviceTimestamp, + const PointerProperties* properties, const PointerCoords* coords, + const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, + float xPrecision, float yPrecision, nsecs_t downTime); + + // Updates pointer coords and properties for pointers with specified ids that have moved. + // Returns true if any of them changed. + bool updateMovedPointers(const PointerProperties* inProperties, const PointerCoords* inCoords, + const uint32_t* inIdToIndex, PointerProperties* outProperties, + PointerCoords* outCoords, const uint32_t* outIdToIndex, + BitSet32 idBits) const; + + bool isPointInsideSurface(int32_t x, int32_t y); + const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); + + static void assignPointerIds(const RawState* last, RawState* current); + + void reportEventForStatistics(nsecs_t evdevTime); + + const char* modeToString(DeviceMode deviceMode); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp new file mode 100644 index 0000000000..a27fab4581 --- /dev/null +++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp @@ -0,0 +1,131 @@ +/* + * 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 "Macros.h" + +#include "VibratorInputMapper.h" + +namespace android { + +VibratorInputMapper::VibratorInputMapper(InputDevice* device) + : InputMapper(device), mVibrating(false) {} + +VibratorInputMapper::~VibratorInputMapper() {} + +uint32_t VibratorInputMapper::getSources() { + return 0; +} + +void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + + info->setVibrator(true); +} + +void VibratorInputMapper::process(const RawEvent* rawEvent) { + // TODO: Handle FF_STATUS, although it does not seem to be widely supported. +} + +void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, + int32_t token) { +#if DEBUG_VIBRATOR + std::string patternStr; + for (size_t i = 0; i < patternSize; i++) { + if (i != 0) { + patternStr += ", "; + } + patternStr += StringPrintf("%" PRId64, pattern[i]); + } + ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", getDeviceId(), + patternStr.c_str(), repeat, token); +#endif + + mVibrating = true; + memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); + mPatternSize = patternSize; + mRepeat = repeat; + mToken = token; + mIndex = -1; + + nextStep(); +} + +void VibratorInputMapper::cancelVibrate(int32_t token) { +#if DEBUG_VIBRATOR + ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); +#endif + + if (mVibrating && mToken == token) { + stopVibrating(); + } +} + +void VibratorInputMapper::timeoutExpired(nsecs_t when) { + if (mVibrating) { + if (when >= mNextStepTime) { + nextStep(); + } else { + getContext()->requestTimeoutAtTime(mNextStepTime); + } + } +} + +void VibratorInputMapper::nextStep() { + mIndex += 1; + if (size_t(mIndex) >= mPatternSize) { + if (mRepeat < 0) { + // We are done. + stopVibrating(); + return; + } + mIndex = mRepeat; + } + + bool vibratorOn = mIndex & 1; + nsecs_t duration = mPattern[mIndex]; + if (vibratorOn) { +#if DEBUG_VIBRATOR + ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration); +#endif + getEventHub()->vibrate(getDeviceId(), duration); + } else { +#if DEBUG_VIBRATOR + ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); +#endif + getEventHub()->cancelVibrate(getDeviceId()); + } + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + mNextStepTime = now + duration; + getContext()->requestTimeoutAtTime(mNextStepTime); +#if DEBUG_VIBRATOR + ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); +#endif +} + +void VibratorInputMapper::stopVibrating() { + mVibrating = false; +#if DEBUG_VIBRATOR + ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); +#endif + getEventHub()->cancelVibrate(getDeviceId()); +} + +void VibratorInputMapper::dump(std::string& dump) { + dump += INDENT2 "Vibrator Input Mapper:\n"; + dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating)); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h new file mode 100644 index 0000000000..6b33f4811e --- /dev/null +++ b/services/inputflinger/reader/mapper/VibratorInputMapper.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_INPUTREADER_VIBRATOR_INPUT_MAPPER_H +#define _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H + +#include "InputMapper.h" + +namespace android { + +class VibratorInputMapper : public InputMapper { +public: + explicit VibratorInputMapper(InputDevice* device); + virtual ~VibratorInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void process(const RawEvent* rawEvent); + + virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); + virtual void cancelVibrate(int32_t token); + virtual void timeoutExpired(nsecs_t when); + virtual void dump(std::string& dump); + +private: + bool mVibrating; + nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; + size_t mPatternSize; + ssize_t mRepeat; + int32_t mToken; + ssize_t mIndex; + nsecs_t mNextStepTime; + + void nextStep(); + void stopVibrating(); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp new file mode 100644 index 0000000000..0337d51126 --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.cpp @@ -0,0 +1,101 @@ +/* + * 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 "CursorButtonAccumulator.h" + +#include "EventHub.h" +#include "InputDevice.h" + +namespace android { + +CursorButtonAccumulator::CursorButtonAccumulator() { + clearButtons(); +} + +void CursorButtonAccumulator::reset(InputDevice* device) { + mBtnLeft = device->isKeyPressed(BTN_LEFT); + mBtnRight = device->isKeyPressed(BTN_RIGHT); + mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); + mBtnBack = device->isKeyPressed(BTN_BACK); + mBtnSide = device->isKeyPressed(BTN_SIDE); + mBtnForward = device->isKeyPressed(BTN_FORWARD); + mBtnExtra = device->isKeyPressed(BTN_EXTRA); + mBtnTask = device->isKeyPressed(BTN_TASK); +} + +void CursorButtonAccumulator::clearButtons() { + mBtnLeft = 0; + mBtnRight = 0; + mBtnMiddle = 0; + mBtnBack = 0; + mBtnSide = 0; + mBtnForward = 0; + mBtnExtra = 0; + mBtnTask = 0; +} + +void CursorButtonAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_KEY) { + switch (rawEvent->code) { + case BTN_LEFT: + mBtnLeft = rawEvent->value; + break; + case BTN_RIGHT: + mBtnRight = rawEvent->value; + break; + case BTN_MIDDLE: + mBtnMiddle = rawEvent->value; + break; + case BTN_BACK: + mBtnBack = rawEvent->value; + break; + case BTN_SIDE: + mBtnSide = rawEvent->value; + break; + case BTN_FORWARD: + mBtnForward = rawEvent->value; + break; + case BTN_EXTRA: + mBtnExtra = rawEvent->value; + break; + case BTN_TASK: + mBtnTask = rawEvent->value; + break; + } + } +} + +uint32_t CursorButtonAccumulator::getButtonState() const { + uint32_t result = 0; + if (mBtnLeft) { + result |= AMOTION_EVENT_BUTTON_PRIMARY; + } + if (mBtnRight) { + result |= AMOTION_EVENT_BUTTON_SECONDARY; + } + if (mBtnMiddle) { + result |= AMOTION_EVENT_BUTTON_TERTIARY; + } + if (mBtnBack || mBtnSide) { + result |= AMOTION_EVENT_BUTTON_BACK; + } + if (mBtnForward || mBtnExtra) { + result |= AMOTION_EVENT_BUTTON_FORWARD; + } + return result; +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h new file mode 100644 index 0000000000..d9123109a3 --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h @@ -0,0 +1,52 @@ +/* + * 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_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H +#define _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H + +#include <stdint.h> + +namespace android { + +class InputDevice; +struct RawEvent; + +/* Keeps track of the state of mouse or touch pad buttons. */ +class CursorButtonAccumulator { +public: + CursorButtonAccumulator(); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + + uint32_t getButtonState() const; + +private: + bool mBtnLeft; + bool mBtnRight; + bool mBtnMiddle; + bool mBtnBack; + bool mBtnSide; + bool mBtnForward; + bool mBtnExtra; + bool mBtnTask; + + void clearButtons(); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp new file mode 100644 index 0000000000..d744096d94 --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.cpp @@ -0,0 +1,59 @@ +/* + * 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 "CursorScrollAccumulator.h" + +#include "EventHub.h" +#include "InputDevice.h" + +namespace android { + +CursorScrollAccumulator::CursorScrollAccumulator() : mHaveRelWheel(false), mHaveRelHWheel(false) { + clearRelativeAxes(); +} + +void CursorScrollAccumulator::configure(InputDevice* device) { + mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); + mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); +} + +void CursorScrollAccumulator::reset(InputDevice* device) { + clearRelativeAxes(); +} + +void CursorScrollAccumulator::clearRelativeAxes() { + mRelWheel = 0; + mRelHWheel = 0; +} + +void CursorScrollAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_REL) { + switch (rawEvent->code) { + case REL_WHEEL: + mRelWheel = rawEvent->value; + break; + case REL_HWHEEL: + mRelHWheel = rawEvent->value; + break; + } + } +} + +void CursorScrollAccumulator::finishSync() { + clearRelativeAxes(); +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h new file mode 100644 index 0000000000..85f331fd8a --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.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_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H +#define _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H + +#include <stdint.h> + +namespace android { + +class InputDevice; +struct RawEvent; + +/* Keeps track of cursor scrolling motions. */ + +class CursorScrollAccumulator { +public: + CursorScrollAccumulator(); + void configure(InputDevice* device); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + void finishSync(); + + inline bool haveRelativeVWheel() const { return mHaveRelWheel; } + inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } + + inline int32_t getRelativeX() const { return mRelX; } + inline int32_t getRelativeY() const { return mRelY; } + inline int32_t getRelativeVWheel() const { return mRelWheel; } + inline int32_t getRelativeHWheel() const { return mRelHWheel; } + +private: + bool mHaveRelWheel; + bool mHaveRelHWheel; + + int32_t mRelX; + int32_t mRelY; + int32_t mRelWheel; + int32_t mRelHWheel; + + void clearRelativeAxes(); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp new file mode 100644 index 0000000000..e9ba727a0d --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp @@ -0,0 +1,76 @@ +/* + * 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 "SingleTouchMotionAccumulator.h" + +#include "EventHub.h" +#include "InputDevice.h" + +namespace android { + +SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { + clearAbsoluteAxes(); +} + +void SingleTouchMotionAccumulator::reset(InputDevice* device) { + mAbsX = device->getAbsoluteAxisValue(ABS_X); + mAbsY = device->getAbsoluteAxisValue(ABS_Y); + mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); + mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); + mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); + mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); + mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); +} + +void SingleTouchMotionAccumulator::clearAbsoluteAxes() { + mAbsX = 0; + mAbsY = 0; + mAbsPressure = 0; + mAbsToolWidth = 0; + mAbsDistance = 0; + mAbsTiltX = 0; + mAbsTiltY = 0; +} + +void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_ABS) { + switch (rawEvent->code) { + case ABS_X: + mAbsX = rawEvent->value; + break; + case ABS_Y: + mAbsY = rawEvent->value; + break; + case ABS_PRESSURE: + mAbsPressure = rawEvent->value; + break; + case ABS_TOOL_WIDTH: + mAbsToolWidth = rawEvent->value; + break; + case ABS_DISTANCE: + mAbsDistance = rawEvent->value; + break; + case ABS_TILT_X: + mAbsTiltX = rawEvent->value; + break; + case ABS_TILT_Y: + mAbsTiltY = rawEvent->value; + break; + } + } +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h new file mode 100644 index 0000000000..75f8a961b3 --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h @@ -0,0 +1,57 @@ +/* + * 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_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H +#define _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H + +#include <stdint.h> + +namespace android { + +class InputDevice; +struct RawEvent; + +/* Keeps track of the state of single-touch protocol. */ +class SingleTouchMotionAccumulator { +public: + SingleTouchMotionAccumulator(); + + void process(const RawEvent* rawEvent); + void reset(InputDevice* device); + + inline int32_t getAbsoluteX() const { return mAbsX; } + inline int32_t getAbsoluteY() const { return mAbsY; } + inline int32_t getAbsolutePressure() const { return mAbsPressure; } + inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } + inline int32_t getAbsoluteDistance() const { return mAbsDistance; } + inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } + inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } + +private: + int32_t mAbsX; + int32_t mAbsY; + int32_t mAbsPressure; + int32_t mAbsToolWidth; + int32_t mAbsDistance; + int32_t mAbsTiltX; + int32_t mAbsTiltY; + + void clearAbsoluteAxes(); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp new file mode 100644 index 0000000000..d2f06c86fd --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp @@ -0,0 +1,162 @@ +/* + * 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 "TouchButtonAccumulator.h" + +#include "EventHub.h" +#include "InputDevice.h" + +namespace android { + +TouchButtonAccumulator::TouchButtonAccumulator() : mHaveBtnTouch(false), mHaveStylus(false) { + clearButtons(); +} + +void TouchButtonAccumulator::configure(InputDevice* device) { + mHaveBtnTouch = device->hasKey(BTN_TOUCH); + mHaveStylus = device->hasKey(BTN_TOOL_PEN) || device->hasKey(BTN_TOOL_RUBBER) || + device->hasKey(BTN_TOOL_BRUSH) || device->hasKey(BTN_TOOL_PENCIL) || + device->hasKey(BTN_TOOL_AIRBRUSH); +} + +void TouchButtonAccumulator::reset(InputDevice* device) { + mBtnTouch = device->isKeyPressed(BTN_TOUCH); + mBtnStylus = device->isKeyPressed(BTN_STYLUS); + // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch + mBtnStylus2 = device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); + mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); + mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); + mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); + mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); + mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); + mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); + mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); + mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); + mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); + mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); + mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); +} + +void TouchButtonAccumulator::clearButtons() { + mBtnTouch = 0; + mBtnStylus = 0; + mBtnStylus2 = 0; + mBtnToolFinger = 0; + mBtnToolPen = 0; + mBtnToolRubber = 0; + mBtnToolBrush = 0; + mBtnToolPencil = 0; + mBtnToolAirbrush = 0; + mBtnToolMouse = 0; + mBtnToolLens = 0; + mBtnToolDoubleTap = 0; + mBtnToolTripleTap = 0; + mBtnToolQuadTap = 0; +} + +void TouchButtonAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_KEY) { + switch (rawEvent->code) { + case BTN_TOUCH: + mBtnTouch = rawEvent->value; + break; + case BTN_STYLUS: + mBtnStylus = rawEvent->value; + break; + case BTN_STYLUS2: + case BTN_0: // BTN_0 is what gets mapped for the HID usage + // Digitizers.SecondaryBarrelSwitch + mBtnStylus2 = rawEvent->value; + break; + case BTN_TOOL_FINGER: + mBtnToolFinger = rawEvent->value; + break; + case BTN_TOOL_PEN: + mBtnToolPen = rawEvent->value; + break; + case BTN_TOOL_RUBBER: + mBtnToolRubber = rawEvent->value; + break; + case BTN_TOOL_BRUSH: + mBtnToolBrush = rawEvent->value; + break; + case BTN_TOOL_PENCIL: + mBtnToolPencil = rawEvent->value; + break; + case BTN_TOOL_AIRBRUSH: + mBtnToolAirbrush = rawEvent->value; + break; + case BTN_TOOL_MOUSE: + mBtnToolMouse = rawEvent->value; + break; + case BTN_TOOL_LENS: + mBtnToolLens = rawEvent->value; + break; + case BTN_TOOL_DOUBLETAP: + mBtnToolDoubleTap = rawEvent->value; + break; + case BTN_TOOL_TRIPLETAP: + mBtnToolTripleTap = rawEvent->value; + break; + case BTN_TOOL_QUADTAP: + mBtnToolQuadTap = rawEvent->value; + break; + } + } +} + +uint32_t TouchButtonAccumulator::getButtonState() const { + uint32_t result = 0; + if (mBtnStylus) { + result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY; + } + if (mBtnStylus2) { + result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY; + } + return result; +} + +int32_t TouchButtonAccumulator::getToolType() const { + if (mBtnToolMouse || mBtnToolLens) { + return AMOTION_EVENT_TOOL_TYPE_MOUSE; + } + if (mBtnToolRubber) { + return AMOTION_EVENT_TOOL_TYPE_ERASER; + } + if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { + return AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { + return AMOTION_EVENT_TOOL_TYPE_FINGER; + } + return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; +} + +bool TouchButtonAccumulator::isToolActive() const { + return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber || mBtnToolBrush || + mBtnToolPencil || mBtnToolAirbrush || mBtnToolMouse || mBtnToolLens || + mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; +} + +bool TouchButtonAccumulator::isHovering() const { + return mHaveBtnTouch && !mBtnTouch; +} + +bool TouchButtonAccumulator::hasStylus() const { + return mHaveStylus; +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h new file mode 100644 index 0000000000..65b6bdcc12 --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h @@ -0,0 +1,66 @@ +/* + * 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_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H +#define _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H + +#include <stdint.h> + +namespace android { + +class InputDevice; +struct RawEvent; + +/* Keeps track of the state of touch, stylus and tool buttons. */ +class TouchButtonAccumulator { +public: + TouchButtonAccumulator(); + void configure(InputDevice* device); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + + uint32_t getButtonState() const; + int32_t getToolType() const; + bool isToolActive() const; + bool isHovering() const; + bool hasStylus() const; + +private: + bool mHaveBtnTouch; + bool mHaveStylus; + + bool mBtnTouch; + bool mBtnStylus; + bool mBtnStylus2; + bool mBtnToolFinger; + bool mBtnToolPen; + bool mBtnToolRubber; + bool mBtnToolBrush; + bool mBtnToolPencil; + bool mBtnToolAirbrush; + bool mBtnToolMouse; + bool mBtnToolLens; + bool mBtnToolDoubleTap; + bool mBtnToolTripleTap; + bool mBtnToolQuadTap; + + void clearButtons(); +}; + +} // namespace android + +#endif // _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H
\ No newline at end of file diff --git a/services/inputflinger/reporter/Android.bp b/services/inputflinger/reporter/Android.bp new file mode 100644 index 0000000000..5956fb0794 --- /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 index 8d3153c367..b591d3f909 100644 --- a/services/inputflinger/InputReporter.cpp +++ b/services/inputflinger/reporter/InputReporter.cpp @@ -27,15 +27,15 @@ public: }; 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 index 906d7f25f2..e5d360609f 100644 --- a/services/inputflinger/include/InputReporterInterface.h +++ b/services/inputflinger/reporter/InputReporterInterface.h @@ -27,7 +27,7 @@ namespace android { */ 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/Android.bp b/services/inputflinger/tests/Android.bp index 9054316204..c4f8626a98 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -32,4 +32,7 @@ cc_test { "libinputflinger_base", "libinputservice", ], + header_libs: [ + "libinputreader_headers", + ], } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 9fe6481ca0..551bee18e8 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -14,14 +14,16 @@ * limitations under the License. */ -#include "../InputDispatcher.h" +#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; @@ -1025,4 +1027,4 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, mFakePolicy->assertOnPointerDownEquals(nullptr); } -} // namespace android +} // namespace android::inputdispatcher diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index d35302885d..aeb4ad62a8 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -14,8 +14,16 @@ * limitations under the License. */ -#include "../InputReader.h" -#include "TestInputListener.h" +#include <CursorInputMapper.h> +#include <InputDevice.h> +#include <InputMapper.h> +#include <InputReader.h> +#include <KeyboardInputMapper.h> +#include <MultiTouchInputMapper.h> +#include <SingleTouchInputMapper.h> +#include <SwitchInputMapper.h> +#include <TestInputListener.h> +#include <TouchInputMapper.h> #include <gtest/gtest.h> #include <inttypes.h> |