diff options
| author | 2010-06-13 17:55:28 -0700 | |
|---|---|---|
| committer | 2010-06-13 17:55:28 -0700 | |
| commit | 7c8aa44f320f45e8417f0aba9ca67af6a67a5cf7 (patch) | |
| tree | 2d547d9d8ddc5b08310070121616294d92ebca70 /include/ui/InputDispatcher.h | |
| parent | 94f14aeca9e6c6d07b39a7f708eacadcfeb6fbd2 (diff) | |
| parent | 46b9ac0ae2162309774a7478cd9d4e578747bfc2 (diff) | |
am 46b9ac0a: Native input dispatch rewrite work in progress.
Merge commit '46b9ac0ae2162309774a7478cd9d4e578747bfc2' into gingerbread
* commit '46b9ac0ae2162309774a7478cd9d4e578747bfc2':
  Native input dispatch rewrite work in progress.
Diffstat (limited to 'include/ui/InputDispatcher.h')
| -rw-r--r-- | include/ui/InputDispatcher.h | 409 | 
1 files changed, 409 insertions, 0 deletions
| diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h new file mode 100644 index 000000000000..bde07f2a090b --- /dev/null +++ b/include/ui/InputDispatcher.h @@ -0,0 +1,409 @@ +/* + * 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 <ui/Input.h> +#include <ui/InputDispatchPolicy.h> +#include <ui/InputTransport.h> +#include <utils/KeyedVector.h> +#include <utils/Vector.h> +#include <utils/threads.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/PollLoop.h> +#include <utils/Pool.h> + +#include <stddef.h> +#include <unistd.h> + + +namespace android { + +/* Notifies the system about input events generated by the input reader. + * The dispatcher is expected to be mostly asynchronous. */ +class InputDispatcherInterface : public virtual RefBase { +protected: +    InputDispatcherInterface() { } +    virtual ~InputDispatcherInterface() { } + +public: +    /* 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; + +    /* Notifies the dispatcher about new events. +     * The dispatcher will process most of these events asynchronously although some +     * policy processing may occur synchronously. +     * +     * These methods should only be called on the input reader thread. +     */ +    virtual void notifyConfigurationChanged(nsecs_t eventTime, +            int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) = 0; +    virtual void notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) = 0; +    virtual void notifyAppSwitchComing(nsecs_t eventTime) = 0; +    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature, +            uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, +            int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0; +    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t nature, +            uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags, +            uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, +            float xPrecision, float yPrecision, nsecs_t downTime) = 0; + +    /* Registers or unregister input channels that may be used as targets for input events. +     * +     * These methods may be called on any thread (usually by the input manager). +     */ +    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel) = 0; +    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; +}; + +/* Dispatches events. */ +class InputDispatcher : public InputDispatcherInterface { +protected: +    virtual ~InputDispatcher(); + +public: +    explicit InputDispatcher(const sp<InputDispatchPolicyInterface>& policy); + +    virtual void dispatchOnce(); + +    virtual void notifyConfigurationChanged(nsecs_t eventTime, +            int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig); +    virtual void notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen); +    virtual void notifyAppSwitchComing(nsecs_t eventTime); +    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature, +            uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, +            int32_t scanCode, int32_t metaState, nsecs_t downTime); +    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t nature, +            uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags, +            uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, +            float xPrecision, float yPrecision, nsecs_t downTime); + +    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel); +    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); + +private: +    template <typename T> +    struct Link { +        T* next; +        T* prev; +    }; + +    struct EventEntry : Link<EventEntry> { +        enum { +            TYPE_SENTINEL, +            TYPE_CONFIGURATION_CHANGED, +            TYPE_KEY, +            TYPE_MOTION +        }; + +        int32_t refCount; +        int32_t type; +        nsecs_t eventTime; +    }; + +    struct ConfigurationChangedEntry : EventEntry { +        int32_t touchScreenConfig; +        int32_t keyboardConfig; +        int32_t navigationConfig; +    }; + +    struct KeyEntry : EventEntry { +        int32_t deviceId; +        int32_t nature; +        uint32_t policyFlags; +        int32_t action; +        int32_t flags; +        int32_t keyCode; +        int32_t scanCode; +        int32_t metaState; +        int32_t repeatCount; +        nsecs_t downTime; +    }; + +    struct MotionSample { +        MotionSample* next; + +        nsecs_t eventTime; +        PointerCoords pointerCoords[MAX_POINTERS]; +    }; + +    struct MotionEntry : EventEntry { +        int32_t deviceId; +        int32_t nature; +        uint32_t policyFlags; +        int32_t action; +        int32_t metaState; +        int32_t edgeFlags; +        float xPrecision; +        float yPrecision; +        nsecs_t downTime; +        uint32_t pointerCount; +        int32_t pointerIds[MAX_POINTERS]; + +        // Linked list of motion samples associated with this motion event. +        MotionSample firstSample; +        MotionSample* lastSample; +    }; + +    struct DispatchEntry : Link<DispatchEntry> { +        EventEntry* eventEntry; // the event to dispatch +        int32_t targetFlags; +        float xOffset; +        float yOffset; +        nsecs_t timeout; + +        // True if dispatch has started. +        bool inProgress; + +        // For motion events: +        //   Pointer to the first motion sample to dispatch in this cycle. +        //   Usually NULL to indicate that the list of motion samples begins at +        //   MotionEntry::firstSample.  Otherwise, some samples were dispatched in a previous +        //   cycle and this pointer indicates the location of the first remainining sample +        //   to dispatch during the current cycle. +        MotionSample* headMotionSample; +        //   Pointer to a motion sample to dispatch in the next cycle if the dispatcher was +        //   unable to send all motion samples during this cycle.  On the next cycle, +        //   headMotionSample will be initialized to tailMotionSample and tailMotionSample +        //   will be set to NULL. +        MotionSample* tailMotionSample; +    }; + +    template <typename T> +    struct Queue { +        T head; +        T tail; + +        inline Queue() { +            head.prev = NULL; +            head.next = & tail; +            tail.prev = & head; +            tail.next = NULL; +        } + +        inline bool isEmpty() { +            return head.next == & tail; +        } + +        inline void enqueueAtTail(T* entry) { +            T* last = tail.prev; +            last->next = entry; +            entry->prev = last; +            entry->next = & tail; +            tail.prev = entry; +        } + +        inline void enqueueAtHead(T* entry) { +            T* first = head.next; +            head.next = entry; +            entry->prev = & head; +            entry->next = first; +            first->prev = entry; +        } + +        inline void dequeue(T* entry) { +            entry->prev->next = entry->next; +            entry->next->prev = entry->prev; +        } + +        inline T* dequeueAtHead() { +            T* first = head.next; +            dequeue(first); +            return first; +        } +    }; + +    /* Allocates queue entries and performs reference counting as needed. */ +    class Allocator { +    public: +        Allocator(); + +        ConfigurationChangedEntry* obtainConfigurationChangedEntry(); +        KeyEntry* obtainKeyEntry(); +        MotionEntry* obtainMotionEntry(); +        DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry); + +        void releaseEventEntry(EventEntry* entry); +        void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry); +        void releaseKeyEntry(KeyEntry* entry); +        void releaseMotionEntry(MotionEntry* entry); +        void releaseDispatchEntry(DispatchEntry* entry); + +        void appendMotionSample(MotionEntry* motionEntry, +                nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords); +        void freeMotionSample(MotionSample* sample); +        void freeMotionSampleList(MotionSample* head); + +    private: +        Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool; +        Pool<KeyEntry> mKeyEntryPool; +        Pool<MotionEntry> mMotionEntryPool; +        Pool<MotionSample> mMotionSamplePool; +        Pool<DispatchEntry> mDispatchEntryPool; +    }; + +    /* 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 client is not responding. +            STATUS_NOT_RESPONDING, +            // The input channel has been unregistered. +            STATUS_ZOMBIE +        }; + +        Status status; +        sp<InputChannel> inputChannel; +        InputPublisher inputPublisher; +        Queue<DispatchEntry> outboundQueue; +        nsecs_t nextTimeoutTime; // next timeout time (LONG_LONG_MAX if none) + +        nsecs_t lastEventTime; // the time when the event was originally captured +        nsecs_t lastDispatchTime; // the time when the last event was dispatched +        nsecs_t lastANRTime; // the time when the last ANR was recorded + +        explicit Connection(const sp<InputChannel>& inputChannel); + +        inline const char* getInputChannelName() { return inputChannel->getName().string(); } + +        // Finds a DispatchEntry in the outbound queue associated with the specified event. +        // Returns NULL if not found. +        DispatchEntry* findQueuedDispatchEntryForEvent(const EventEntry* eventEntry) const; + +        // Determine whether this connection has a pending synchronous dispatch target. +        // Since there can only ever be at most one such target at a time, if there is one, +        // it must be at the tail because nothing else can be enqueued after it. +        inline bool hasPendingSyncTarget() { +            return ! outboundQueue.isEmpty() +                    && (outboundQueue.tail.prev->targetFlags & InputTarget::FLAG_SYNC); +        } + +        // Gets the time since the current event was originally obtained from the input driver. +        inline double getEventLatencyMillis(nsecs_t currentTime) { +            return (currentTime - lastEventTime) / 1000000.0; +        } + +        // Gets the time since the current event entered the outbound dispatch queue. +        inline double getDispatchLatencyMillis(nsecs_t currentTime) { +            return (currentTime - lastDispatchTime) / 1000000.0; +        } + +        // Gets the time since the current event ANR was declared, if applicable. +        inline double getANRLatencyMillis(nsecs_t currentTime) { +            return (currentTime - lastANRTime) / 1000000.0; +        } + +        status_t initialize(); +    }; + +    sp<InputDispatchPolicyInterface> mPolicy; + +    Mutex mLock; + +    Queue<EventEntry> mInboundQueue; +    Allocator mAllocator; + +    sp<PollLoop> mPollLoop; + +    // All registered connections mapped by receive pipe file descriptor. +    KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd; + +    // Active connections are connections that have a non-empty outbound queue. +    Vector<Connection*> mActiveConnections; + +    // Pool of key and motion event objects used only to ask the input dispatch policy +    // for the targets of an event that is to be dispatched. +    KeyEvent mReusableKeyEvent; +    MotionEvent mReusableMotionEvent; + +    // The input targets that were most recently identified for dispatch. +    // If there is a synchronous event dispatch in progress, the current input targets will +    // remain unchanged until the dispatch has completed or been aborted. +    Vector<InputTarget> mCurrentInputTargets; + +    // Key repeat tracking. +    // XXX Move this up to the input reader instead. +    struct KeyRepeatState { +        KeyEntry* lastKeyEntry; // or null if no repeat +        nsecs_t nextRepeatTime; +    } mKeyRepeatState; + +    void resetKeyRepeatLocked(); + +    // Process events that have just been dequeued from the head of the input queue. +    void processConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry); +    void processKeyLocked(nsecs_t currentTime, KeyEntry* entry); +    void processKeyRepeatLocked(nsecs_t currentTime); +    void processMotionLocked(nsecs_t currentTime, MotionEntry* entry); + +    // Identify input targets for an event and dispatch to them. +    void identifyInputTargetsAndDispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry); +    void identifyInputTargetsAndDispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry); +    void dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime, EventEntry* entry, +            bool resumeWithAppendedMotionSample); + +    // Manage the dispatch cycle for a single connection. +    void prepareDispatchCycleLocked(nsecs_t currentTime, Connection* connection, +            EventEntry* eventEntry, const InputTarget* inputTarget, +            bool resumeWithAppendedMotionSample); +    void startDispatchCycleLocked(nsecs_t currentTime, Connection* connection); +    void finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection); +    bool timeoutDispatchCycleLocked(nsecs_t currentTime, Connection* connection); +    bool abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection, +            bool broken); +    static bool handleReceiveCallback(int receiveFd, int events, void* data); + +    // Add or remove a connection to the mActiveConnections vector. +    void activateConnectionLocked(Connection* connection); +    void deactivateConnectionLocked(Connection* connection); + +    // Interesting events that we might like to log or tell the framework about. +    void onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection); +    void onDispatchCycleFinishedLocked(nsecs_t currentTime, Connection* connection, +            bool recoveredFromANR); +    void onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection); +    void onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection); +}; + +/* 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_PRIV_H |