Merge "More work in progress on native events." into gingerbread
This commit is contained in:
@ -21,6 +21,9 @@
|
||||
// Log debug messages about the dispatch cycle.
|
||||
#define DEBUG_DISPATCH_CYCLE 1
|
||||
|
||||
// Log debug messages about registrations.
|
||||
#define DEBUG_REGISTRATION 1
|
||||
|
||||
|
||||
#include "JNIHelp.h"
|
||||
|
||||
@ -51,7 +54,7 @@ static struct {
|
||||
class NativeInputQueue {
|
||||
public:
|
||||
NativeInputQueue();
|
||||
virtual ~NativeInputQueue();
|
||||
~NativeInputQueue();
|
||||
|
||||
status_t registerInputChannel(JNIEnv* env, jobject inputChannelObj,
|
||||
jobject inputHandlerObj, jobject messageQueueObj);
|
||||
@ -75,7 +78,7 @@ private:
|
||||
|
||||
Connection(const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop);
|
||||
|
||||
inline const char* getInputChannelName() { return inputChannel->getName().string(); }
|
||||
inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
|
||||
|
||||
Status status;
|
||||
|
||||
@ -125,6 +128,10 @@ status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChanne
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
#if DEBUG_REGISTRATION
|
||||
LOGD("channel '%s' - Registered", inputChannel->getName().string());
|
||||
#endif
|
||||
|
||||
sp<PollLoop> pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueueObj);
|
||||
|
||||
int receiveFd;
|
||||
@ -154,7 +161,7 @@ status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChanne
|
||||
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
|
||||
handleInputChannelDisposed, this);
|
||||
|
||||
pollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, NULL);
|
||||
pollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -166,6 +173,10 @@ status_t NativeInputQueue::unregisterInputChannel(JNIEnv* env, jobject inputChan
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
#if DEBUG_REGISTRATION
|
||||
LOGD("channel '%s' - Unregistered", inputChannel->getName().string());
|
||||
#endif
|
||||
|
||||
int32_t receiveFd;
|
||||
sp<Connection> connection;
|
||||
{ // acquire lock
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "JNIHelp.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <ui/InputDispatchPolicy.h>
|
||||
#include <ui/InputDispatcher.h>
|
||||
#include <ui/InputTransport.h>
|
||||
#include "android_view_InputTarget.h"
|
||||
#include "android_view_InputChannel.h"
|
||||
|
@ -73,7 +73,7 @@ enum {
|
||||
POLICY_FLAG_MENU = 0x00000040,
|
||||
POLICY_FLAG_LAUNCHER = 0x00000080,
|
||||
|
||||
/* These flags are set by the input dispatch policy as it intercepts each event. */
|
||||
/* These flags are set by the input reader policy as it intercepts each event. */
|
||||
|
||||
// Indicates that the screen was off when the event was received and the event
|
||||
// should wake the device.
|
||||
@ -84,6 +84,37 @@ enum {
|
||||
POLICY_FLAG_BRIGHT_HERE = 0x20000000,
|
||||
};
|
||||
|
||||
/*
|
||||
* Describes the basic configuration of input devices that are present.
|
||||
*/
|
||||
struct InputConfiguration {
|
||||
enum {
|
||||
TOUCHSCREEN_UNDEFINED = 0,
|
||||
TOUCHSCREEN_NOTOUCH = 1,
|
||||
TOUCHSCREEN_STYLUS = 2,
|
||||
TOUCHSCREEN_FINGER = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
KEYBOARD_UNDEFINED = 0,
|
||||
KEYBOARD_NOKEYS = 1,
|
||||
KEYBOARD_QWERTY = 2,
|
||||
KEYBOARD_12KEY = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
NAVIGATION_UNDEFINED = 0,
|
||||
NAVIGATION_NONAV = 1,
|
||||
NAVIGATION_DPAD = 2,
|
||||
NAVIGATION_TRACKBALL = 3,
|
||||
NAVIGATION_WHEEL = 4
|
||||
};
|
||||
|
||||
int32_t touchScreen;
|
||||
int32_t keyboard;
|
||||
int32_t navigation;
|
||||
};
|
||||
|
||||
/*
|
||||
* Pointer coordinate data.
|
||||
*/
|
||||
|
@ -1,198 +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_DISPATCH_POLICY_H
|
||||
#define _UI_INPUT_DISPATCH_POLICY_H
|
||||
|
||||
/**
|
||||
* Native input dispatch policy.
|
||||
*/
|
||||
|
||||
#include <ui/Input.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class InputChannel;
|
||||
|
||||
/*
|
||||
* 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 subsequent event delivery should be held until the
|
||||
* current event is delivered to this target or a timeout occurs. */
|
||||
FLAG_SYNC = 0x01,
|
||||
|
||||
/* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of
|
||||
* this target and so should instead be delivered as an ACTION_OUTSIDE to this target. */
|
||||
FLAG_OUTSIDE = 0x02,
|
||||
|
||||
/* This flag indicates that a KeyEvent or MotionEvent is being canceled.
|
||||
* In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set.
|
||||
* In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL. */
|
||||
FLAG_CANCEL = 0x04
|
||||
};
|
||||
|
||||
// The input channel to be targeted.
|
||||
sp<InputChannel> inputChannel;
|
||||
|
||||
// Flags for the input target.
|
||||
int32_t flags;
|
||||
|
||||
// The timeout for event delivery to this target in nanoseconds. Or -1 if none.
|
||||
nsecs_t timeout;
|
||||
|
||||
// The x and y offset to add to a MotionEvent as it is delivered.
|
||||
// (ignored for KeyEvents)
|
||||
float xOffset, yOffset;
|
||||
};
|
||||
|
||||
/*
|
||||
* Input dispatch policy interface.
|
||||
*
|
||||
* The input dispatch policy is used by the input dispatcher to interact with the
|
||||
* Window Manager and other system components. This separation of concerns keeps
|
||||
* the input dispatcher relatively free of special case logic such as is required
|
||||
* to determine the target of iput events, when to wake the device, how to interact
|
||||
* with key guard, and when to transition to the home screen.
|
||||
*
|
||||
* The actual implementation is partially supported by callbacks into the DVM
|
||||
* via JNI. This class is also mocked in the input dispatcher unit tests since
|
||||
* it is an ideal test seam.
|
||||
*/
|
||||
class InputDispatchPolicyInterface : public virtual RefBase {
|
||||
protected:
|
||||
InputDispatchPolicyInterface() { }
|
||||
virtual ~InputDispatchPolicyInterface() { }
|
||||
|
||||
public:
|
||||
enum {
|
||||
ROTATION_0 = 0,
|
||||
ROTATION_90 = 1,
|
||||
ROTATION_180 = 2,
|
||||
ROTATION_270 = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
// The input dispatcher should do nothing and discard the input unless other
|
||||
// flags are set.
|
||||
ACTION_NONE = 0,
|
||||
|
||||
// The input dispatcher should dispatch the input to the application.
|
||||
ACTION_DISPATCH = 0x00000001,
|
||||
|
||||
// The input dispatcher should perform special filtering in preparation for
|
||||
// a pending app switch.
|
||||
ACTION_APP_SWITCH_COMING = 0x00000002,
|
||||
|
||||
// The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it
|
||||
// passes through the dispatch pipeline.
|
||||
ACTION_WOKE_HERE = 0x00000004,
|
||||
|
||||
// The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
|
||||
// passes through the dispatch pipeline.
|
||||
ACTION_BRIGHT_HERE = 0x00000008
|
||||
};
|
||||
|
||||
enum {
|
||||
TOUCHSCREEN_UNDEFINED = 0,
|
||||
TOUCHSCREEN_NOTOUCH = 1,
|
||||
TOUCHSCREEN_STYLUS = 2,
|
||||
TOUCHSCREEN_FINGER = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
KEYBOARD_UNDEFINED = 0,
|
||||
KEYBOARD_NOKEYS = 1,
|
||||
KEYBOARD_QWERTY = 2,
|
||||
KEYBOARD_12KEY = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
NAVIGATION_UNDEFINED = 0,
|
||||
NAVIGATION_NONAV = 1,
|
||||
NAVIGATION_DPAD = 2,
|
||||
NAVIGATION_TRACKBALL = 3,
|
||||
NAVIGATION_WHEEL = 4
|
||||
};
|
||||
|
||||
struct VirtualKeyDefinition {
|
||||
int32_t scanCode;
|
||||
|
||||
// configured position data, specified in display coords
|
||||
int32_t centerX;
|
||||
int32_t centerY;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
};
|
||||
|
||||
/* Gets information about the display with the specified id.
|
||||
* Returns true if the display info is available, false otherwise.
|
||||
*/
|
||||
virtual bool getDisplayInfo(int32_t displayId,
|
||||
int32_t* width, int32_t* height, int32_t* orientation) = 0;
|
||||
|
||||
virtual void notifyConfigurationChanged(nsecs_t when,
|
||||
int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) = 0;
|
||||
|
||||
virtual void notifyLidSwitchChanged(nsecs_t when, bool lidOpen) = 0;
|
||||
|
||||
virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
|
||||
int32_t action, int32_t flags, int32_t keyCode,
|
||||
int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
|
||||
|
||||
virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
|
||||
bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0;
|
||||
|
||||
virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
|
||||
bool rolled) = 0;
|
||||
|
||||
virtual int32_t interceptTouch(nsecs_t when) = 0;
|
||||
|
||||
virtual bool allowKeyRepeat() = 0;
|
||||
virtual nsecs_t getKeyRepeatTimeout() = 0;
|
||||
|
||||
virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
|
||||
Vector<InputTarget>& outTargets) = 0;
|
||||
virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
|
||||
Vector<InputTarget>& outTargets) = 0;
|
||||
|
||||
/* Determine whether to turn on some hacks we have to improve the touch interaction with a
|
||||
* certain device whose screen currently is not all that good.
|
||||
*/
|
||||
virtual bool filterTouchEvents() = 0;
|
||||
|
||||
/* Determine whether to turn on some hacks to improve touch interaction with another device
|
||||
* where touch coordinate data can get corrupted.
|
||||
*/
|
||||
virtual bool filterJumpyTouchEvents() = 0;
|
||||
|
||||
virtual void getVirtualKeyDefinitions(const String8& deviceName,
|
||||
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
|
||||
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_INPUT_DISPATCH_POLICY_H
|
@ -18,7 +18,6 @@
|
||||
#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>
|
||||
@ -35,6 +34,82 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* 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 subsequent event delivery should be held until the
|
||||
* current event is delivered to this target or a timeout occurs. */
|
||||
FLAG_SYNC = 0x01,
|
||||
|
||||
/* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of
|
||||
* this target and so should instead be delivered as an ACTION_OUTSIDE to this target. */
|
||||
FLAG_OUTSIDE = 0x02,
|
||||
|
||||
/* This flag indicates that a KeyEvent or MotionEvent is being canceled.
|
||||
* In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set.
|
||||
* In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL. */
|
||||
FLAG_CANCEL = 0x04
|
||||
};
|
||||
|
||||
// The input channel to be targeted.
|
||||
sp<InputChannel> inputChannel;
|
||||
|
||||
// Flags for the input target.
|
||||
int32_t flags;
|
||||
|
||||
// The timeout for event delivery to this target in nanoseconds. Or -1 if none.
|
||||
nsecs_t timeout;
|
||||
|
||||
// The x and y offset to add to a MotionEvent as it is delivered.
|
||||
// (ignored for KeyEvents)
|
||||
float xOffset, yOffset;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 input channel is unrecoverably broken. */
|
||||
virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0;
|
||||
|
||||
/* Notifies the system that an input channel is not responding. */
|
||||
virtual void notifyInputChannelANR(const sp<InputChannel>& inputChannel) = 0;
|
||||
|
||||
/* Notifies the system that an input channel recovered from ANR. */
|
||||
virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) = 0;
|
||||
|
||||
/* Gets the key repeat timeout or -1 if automatic key repeating is disabled. */
|
||||
virtual nsecs_t getKeyRepeatTimeout() = 0;
|
||||
|
||||
/* Gets the input targets for a key event. */
|
||||
virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
|
||||
Vector<InputTarget>& outTargets) = 0;
|
||||
|
||||
/* Gets the input targets for a motion event. */
|
||||
virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
|
||||
Vector<InputTarget>& outTargets) = 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 {
|
||||
@ -51,14 +126,10 @@ public:
|
||||
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 notifyConfigurationChanged(nsecs_t eventTime) = 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,
|
||||
@ -76,19 +147,33 @@ public:
|
||||
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
|
||||
};
|
||||
|
||||
/* Dispatches events. */
|
||||
/* 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<InputDispatchPolicyInterface>& policy);
|
||||
explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& 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 notifyConfigurationChanged(nsecs_t eventTime);
|
||||
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,
|
||||
@ -119,12 +204,11 @@ private:
|
||||
int32_t refCount;
|
||||
int32_t type;
|
||||
nsecs_t eventTime;
|
||||
|
||||
bool dispatchInProgress; // initially false, set to true while dispatching
|
||||
};
|
||||
|
||||
struct ConfigurationChangedEntry : EventEntry {
|
||||
int32_t touchScreenConfig;
|
||||
int32_t keyboardConfig;
|
||||
int32_t navigationConfig;
|
||||
};
|
||||
|
||||
struct KeyEntry : EventEntry {
|
||||
@ -165,6 +249,7 @@ private:
|
||||
MotionSample* lastSample;
|
||||
};
|
||||
|
||||
// Tracks the progress of dispatching a particular event to a particular connection.
|
||||
struct DispatchEntry : Link<DispatchEntry> {
|
||||
EventEntry* eventEntry; // the event to dispatch
|
||||
int32_t targetFlags;
|
||||
@ -189,6 +274,36 @@ private:
|
||||
MotionSample* tailMotionSample;
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
struct CommandEntry : Link<CommandEntry> {
|
||||
CommandEntry();
|
||||
~CommandEntry();
|
||||
|
||||
Command command;
|
||||
|
||||
// parameters for the command (usage varies by command)
|
||||
sp<InputChannel> inputChannel;
|
||||
};
|
||||
|
||||
// Generic queue implementation.
|
||||
template <typename T>
|
||||
struct Queue {
|
||||
T head;
|
||||
@ -242,17 +357,17 @@ private:
|
||||
KeyEntry* obtainKeyEntry();
|
||||
MotionEntry* obtainMotionEntry();
|
||||
DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry);
|
||||
CommandEntry* obtainCommandEntry(Command command);
|
||||
|
||||
void releaseEventEntry(EventEntry* entry);
|
||||
void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry);
|
||||
void releaseKeyEntry(KeyEntry* entry);
|
||||
void releaseMotionEntry(MotionEntry* entry);
|
||||
void releaseDispatchEntry(DispatchEntry* entry);
|
||||
void releaseCommandEntry(CommandEntry* 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;
|
||||
@ -260,6 +375,7 @@ private:
|
||||
Pool<MotionEntry> mMotionEntryPool;
|
||||
Pool<MotionSample> mMotionSamplePool;
|
||||
Pool<DispatchEntry> mDispatchEntryPool;
|
||||
Pool<CommandEntry> mCommandEntryPool;
|
||||
};
|
||||
|
||||
/* Manages the dispatch state associated with a single input channel. */
|
||||
@ -291,7 +407,9 @@ private:
|
||||
|
||||
explicit Connection(const sp<InputChannel>& inputChannel);
|
||||
|
||||
inline const char* getInputChannelName() { return inputChannel->getName().string(); }
|
||||
inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
|
||||
|
||||
const char* getStatusLabel() const;
|
||||
|
||||
// Finds a DispatchEntry in the outbound queue associated with the specified event.
|
||||
// Returns NULL if not found.
|
||||
@ -323,22 +441,23 @@ private:
|
||||
status_t initialize();
|
||||
};
|
||||
|
||||
sp<InputDispatchPolicyInterface> mPolicy;
|
||||
sp<InputDispatcherPolicyInterface> mPolicy;
|
||||
|
||||
Mutex mLock;
|
||||
|
||||
Queue<EventEntry> mInboundQueue;
|
||||
Allocator mAllocator;
|
||||
|
||||
sp<PollLoop> mPollLoop;
|
||||
|
||||
Queue<EventEntry> mInboundQueue;
|
||||
Queue<CommandEntry> mCommandQueue;
|
||||
|
||||
// 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
|
||||
// Preallocated key and motion event objects used only to ask the input dispatcher policy
|
||||
// for the targets of an event that is to be dispatched.
|
||||
KeyEvent mReusableKeyEvent;
|
||||
MotionEvent mReusableMotionEvent;
|
||||
@ -347,6 +466,7 @@ private:
|
||||
// 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;
|
||||
bool mCurrentInputTargetsValid; // false while targets are being recomputed
|
||||
|
||||
// Key repeat tracking.
|
||||
// XXX Move this up to the input reader instead.
|
||||
@ -357,17 +477,27 @@ private:
|
||||
|
||||
void resetKeyRepeatLocked();
|
||||
|
||||
// Deferred command processing.
|
||||
bool runCommandsLockedInterruptible();
|
||||
CommandEntry* postCommandLocked(Command command);
|
||||
|
||||
// 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);
|
||||
void processConfigurationChangedLockedInterruptible(
|
||||
nsecs_t currentTime, ConfigurationChangedEntry* entry);
|
||||
void processKeyLockedInterruptible(
|
||||
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout);
|
||||
void processKeyRepeatLockedInterruptible(
|
||||
nsecs_t currentTime, nsecs_t keyRepeatTimeout);
|
||||
void processMotionLockedInterruptible(
|
||||
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);
|
||||
void identifyInputTargetsAndDispatchKeyLockedInterruptible(
|
||||
nsecs_t currentTime, KeyEntry* entry);
|
||||
void identifyInputTargetsAndDispatchMotionLockedInterruptible(
|
||||
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,
|
||||
@ -384,12 +514,22 @@ private:
|
||||
void activateConnectionLocked(Connection* connection);
|
||||
void deactivateConnectionLocked(Connection* connection);
|
||||
|
||||
// Outbound policy interactions.
|
||||
void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
|
||||
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
|
||||
void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry);
|
||||
void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry);
|
||||
};
|
||||
|
||||
/* Enqueues and dispatches input events, endlessly. */
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
#include <ui/EventHub.h>
|
||||
#include <ui/Input.h>
|
||||
#include <ui/InputDispatchPolicy.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/Timers.h>
|
||||
@ -32,9 +31,14 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
class InputReader;
|
||||
class InputDispatcher;
|
||||
class InputChannel;
|
||||
|
||||
class InputReaderInterface;
|
||||
class InputReaderPolicyInterface;
|
||||
class InputReaderThread;
|
||||
|
||||
class InputDispatcherInterface;
|
||||
class InputDispatcherPolicyInterface;
|
||||
class InputDispatcherThread;
|
||||
|
||||
/*
|
||||
@ -74,8 +78,11 @@ public:
|
||||
/* Unregisters an input channel. */
|
||||
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
|
||||
|
||||
/* Gets input device configuration. */
|
||||
virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0;
|
||||
|
||||
/*
|
||||
* Query current input state.
|
||||
* Queries current input state.
|
||||
* deviceId may be -1 to search for the device automatically, filtered by class.
|
||||
* deviceClasses may be -1 to ignore device class while searching.
|
||||
*/
|
||||
@ -86,7 +93,7 @@ public:
|
||||
virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t sw) const = 0;
|
||||
|
||||
/* Determine whether physical keys exist for the given framework-domain key codes. */
|
||||
/* Determines whether physical keys exist for the given framework-domain key codes. */
|
||||
virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
|
||||
};
|
||||
|
||||
@ -95,12 +102,15 @@ protected:
|
||||
virtual ~InputManager();
|
||||
|
||||
public:
|
||||
/*
|
||||
* Creates an input manager that reads events from the given
|
||||
* event hub and applies the given input dispatch policy.
|
||||
*/
|
||||
InputManager(const sp<EventHubInterface>& eventHub,
|
||||
const sp<InputDispatchPolicyInterface>& policy);
|
||||
InputManager(
|
||||
const sp<EventHubInterface>& eventHub,
|
||||
const sp<InputReaderPolicyInterface>& readerPolicy,
|
||||
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy);
|
||||
|
||||
// (used for testing purposes)
|
||||
InputManager(
|
||||
const sp<InputReaderInterface>& reader,
|
||||
const sp<InputDispatcherInterface>& dispatcher);
|
||||
|
||||
virtual status_t start();
|
||||
virtual status_t stop();
|
||||
@ -108,6 +118,7 @@ public:
|
||||
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
|
||||
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
|
||||
|
||||
virtual void getInputConfiguration(InputConfiguration* outConfiguration) const;
|
||||
virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t scanCode) const;
|
||||
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
@ -117,16 +128,13 @@ public:
|
||||
virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
|
||||
|
||||
private:
|
||||
sp<EventHubInterface> mEventHub;
|
||||
sp<InputDispatchPolicyInterface> mPolicy;
|
||||
|
||||
sp<InputDispatcher> mDispatcher;
|
||||
sp<InputDispatcherThread> mDispatcherThread;
|
||||
|
||||
sp<InputReader> mReader;
|
||||
sp<InputReaderInterface> mReader;
|
||||
sp<InputReaderThread> mReaderThread;
|
||||
|
||||
void configureExcludedDevices();
|
||||
sp<InputDispatcherInterface> mDispatcher;
|
||||
sp<InputDispatcherThread> mDispatcherThread;
|
||||
|
||||
void initialize();
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include <ui/EventHub.h>
|
||||
#include <ui/Input.h>
|
||||
#include <ui/InputDispatchPolicy.h>
|
||||
#include <ui/InputDispatcher.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/threads.h>
|
||||
@ -35,21 +34,6 @@
|
||||
* (This is limited by our use of BitSet32 to track pointer assignments.) */
|
||||
#define MAX_POINTER_ID 32
|
||||
|
||||
/** Amount that trackball needs to move in order to generate a key event. */
|
||||
#define TRACKBALL_MOVEMENT_THRESHOLD 6
|
||||
|
||||
/* Slop distance for jumpy pointer detection.
|
||||
* The vertical range of the screen divided by this is our epsilon value. */
|
||||
#define JUMPY_EPSILON_DIVISOR 212
|
||||
|
||||
/* Number of jumpy points to drop for touchscreens that need it. */
|
||||
#define JUMPY_TRANSITION_DROPS 3
|
||||
#define JUMPY_DROP_LIMIT 3
|
||||
|
||||
/* Maximum squared distance for averaging.
|
||||
* If moving farther than this, turn of averaging to avoid lag in response. */
|
||||
#define AVERAGING_DISTANCE_LIMIT (75 * 75)
|
||||
|
||||
/* Maximum number of historical samples to average. */
|
||||
#define AVERAGING_HISTORY_SIZE 5
|
||||
|
||||
@ -335,8 +319,129 @@ struct InputDevice {
|
||||
};
|
||||
|
||||
|
||||
/* Processes raw input events and sends cooked event data to an input dispatcher
|
||||
* in accordance with the input dispatch policy. */
|
||||
/*
|
||||
* Input reader 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 InputReaderPolicyInterface : public virtual RefBase {
|
||||
protected:
|
||||
InputReaderPolicyInterface() { }
|
||||
virtual ~InputReaderPolicyInterface() { }
|
||||
|
||||
public:
|
||||
/* Display orientations. */
|
||||
enum {
|
||||
ROTATION_0 = 0,
|
||||
ROTATION_90 = 1,
|
||||
ROTATION_180 = 2,
|
||||
ROTATION_270 = 3
|
||||
};
|
||||
|
||||
/* Actions returned by interceptXXX methods. */
|
||||
enum {
|
||||
// The input dispatcher should do nothing and discard the input unless other
|
||||
// flags are set.
|
||||
ACTION_NONE = 0,
|
||||
|
||||
// The input dispatcher should dispatch the input to the application.
|
||||
ACTION_DISPATCH = 0x00000001,
|
||||
|
||||
// The input dispatcher should perform special filtering in preparation for
|
||||
// a pending app switch.
|
||||
ACTION_APP_SWITCH_COMING = 0x00000002,
|
||||
|
||||
// The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it
|
||||
// passes through the dispatch pipeline.
|
||||
ACTION_WOKE_HERE = 0x00000004,
|
||||
|
||||
// The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
|
||||
// passes through the dispatch pipeline.
|
||||
ACTION_BRIGHT_HERE = 0x00000008
|
||||
};
|
||||
|
||||
/* Describes a virtual key. */
|
||||
struct VirtualKeyDefinition {
|
||||
int32_t scanCode;
|
||||
|
||||
// configured position data, specified in display coords
|
||||
int32_t centerX;
|
||||
int32_t centerY;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
};
|
||||
|
||||
/* Gets information about the display with the specified id.
|
||||
* Returns true if the display info is available, false otherwise.
|
||||
*/
|
||||
virtual bool getDisplayInfo(int32_t displayId,
|
||||
int32_t* width, int32_t* height, int32_t* orientation) = 0;
|
||||
|
||||
/* Provides feedback for a virtual key.
|
||||
*/
|
||||
virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
|
||||
int32_t action, int32_t flags, int32_t keyCode,
|
||||
int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
|
||||
|
||||
/* Intercepts a key event.
|
||||
* The policy can use this method as an opportunity to perform power management functions
|
||||
* and early event preprocessing.
|
||||
*
|
||||
* Returns a policy action constant such as ACTION_DISPATCH.
|
||||
*/
|
||||
virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
|
||||
bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0;
|
||||
|
||||
/* Intercepts a trackball event.
|
||||
* The policy can use this method as an opportunity to perform power management functions
|
||||
* and early event preprocessing.
|
||||
*
|
||||
* Returns a policy action constant such as ACTION_DISPATCH.
|
||||
*/
|
||||
virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
|
||||
bool rolled) = 0;
|
||||
|
||||
/* Intercepts a touch event.
|
||||
* The policy can use this method as an opportunity to perform power management functions
|
||||
* and early event preprocessing.
|
||||
*
|
||||
* Returns a policy action constant such as ACTION_DISPATCH.
|
||||
*/
|
||||
virtual int32_t interceptTouch(nsecs_t when) = 0;
|
||||
|
||||
/* Intercepts a switch event.
|
||||
* The policy can use this method as an opportunity to perform power management functions
|
||||
* and early event preprocessing.
|
||||
*
|
||||
* Switches are not dispatched to applications so this method should
|
||||
* usually return ACTION_NONE.
|
||||
*/
|
||||
virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) = 0;
|
||||
|
||||
/* Determines whether to turn on some hacks we have to improve the touch interaction with a
|
||||
* certain device whose screen currently is not all that good.
|
||||
*/
|
||||
virtual bool filterTouchEvents() = 0;
|
||||
|
||||
/* Determines whether to turn on some hacks to improve touch interaction with another device
|
||||
* where touch coordinate data can get corrupted.
|
||||
*/
|
||||
virtual bool filterJumpyTouchEvents() = 0;
|
||||
|
||||
/* Gets the configured virtual key definitions for an input device. */
|
||||
virtual void getVirtualKeyDefinitions(const String8& deviceName,
|
||||
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
|
||||
|
||||
/* Gets the excluded device names for the platform. */
|
||||
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
|
||||
};
|
||||
|
||||
|
||||
/* Processes raw input events and sends cooked event data to an input dispatcher. */
|
||||
class InputReaderInterface : public virtual RefBase {
|
||||
protected:
|
||||
InputReaderInterface() { }
|
||||
@ -355,16 +460,42 @@ public:
|
||||
* This method may be called on any thread (usually by the input manager).
|
||||
*/
|
||||
virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const = 0;
|
||||
|
||||
/* Gets the current input device configuration.
|
||||
*
|
||||
* This method may be called on any thread (usually by the input manager).
|
||||
*/
|
||||
virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const = 0;
|
||||
|
||||
/*
|
||||
* Query current input state.
|
||||
* deviceId may be -1 to search for the device automatically, filtered by class.
|
||||
* deviceClasses may be -1 to ignore device class while searching.
|
||||
*/
|
||||
virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t scanCode) const = 0;
|
||||
virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t keyCode) const = 0;
|
||||
virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t sw) const = 0;
|
||||
|
||||
/* Determine whether physical keys exist for the given framework-domain key codes. */
|
||||
virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
|
||||
};
|
||||
|
||||
|
||||
/* The input reader reads raw event data from the event hub and processes it into input events
|
||||
* that it sends to the input dispatcher. Some functions of the input reader are controlled
|
||||
* by the input dispatch policy, such as early event filtering in low power states.
|
||||
* that it sends to the input dispatcher. Some functions of the input reader, such as early
|
||||
* event filtering in low power states, are controlled by a separate policy object.
|
||||
*
|
||||
* IMPORTANT INVARIANT:
|
||||
* Because the policy can potentially block or cause re-entrance into the input reader,
|
||||
* the input reader never calls into the policy while holding its internal locks.
|
||||
*/
|
||||
class InputReader : public InputReaderInterface {
|
||||
public:
|
||||
InputReader(const sp<EventHubInterface>& eventHub,
|
||||
const sp<InputDispatchPolicyInterface>& policy,
|
||||
const sp<InputReaderPolicyInterface>& policy,
|
||||
const sp<InputDispatcherInterface>& dispatcher);
|
||||
virtual ~InputReader();
|
||||
|
||||
@ -372,6 +503,17 @@ public:
|
||||
|
||||
virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const;
|
||||
|
||||
virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const;
|
||||
|
||||
virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t scanCode) const;
|
||||
virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t keyCode) const;
|
||||
virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t sw) const;
|
||||
|
||||
virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
|
||||
|
||||
private:
|
||||
// Lock that must be acquired while manipulating state that may be concurrently accessed
|
||||
// from other threads by input state query methods. It should be held for as short a
|
||||
@ -383,15 +525,18 @@ private:
|
||||
// (but not other internal device state)
|
||||
mutable Mutex mExportedStateLock;
|
||||
|
||||
// current virtual key information
|
||||
int32_t mGlobalVirtualKeyCode;
|
||||
int32_t mGlobalVirtualScanCode;
|
||||
// current virtual key information (lock mExportedStateLock)
|
||||
int32_t mExportedVirtualKeyCode;
|
||||
int32_t mExportedVirtualScanCode;
|
||||
|
||||
// current input configuration (lock mExportedStateLock)
|
||||
InputConfiguration mExportedInputConfiguration;
|
||||
|
||||
// combined key meta state
|
||||
int32_t mGlobalMetaState;
|
||||
|
||||
sp<EventHubInterface> mEventHub;
|
||||
sp<InputDispatchPolicyInterface> mPolicy;
|
||||
sp<InputReaderPolicyInterface> mPolicy;
|
||||
sp<InputDispatcherInterface> mDispatcher;
|
||||
|
||||
KeyedVector<int32_t, InputDevice*> mDevices;
|
||||
@ -414,7 +559,7 @@ private:
|
||||
// input policy processing and dispatch
|
||||
void onKey(nsecs_t when, InputDevice* device, bool down,
|
||||
int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
|
||||
void onSwitch(nsecs_t when, InputDevice* device, bool down, int32_t code);
|
||||
void onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode, int32_t switchValue);
|
||||
void onSingleTouchScreenStateChanged(nsecs_t when, InputDevice* device);
|
||||
void onMultiTouchScreenStateChanged(nsecs_t when, InputDevice* device);
|
||||
void onTouchScreenChanged(nsecs_t when, InputDevice* device, bool havePointerIds);
|
||||
@ -445,13 +590,17 @@ private:
|
||||
void configureVirtualKeys(InputDevice* device);
|
||||
void configureAbsoluteAxisInfo(InputDevice* device, int axis, const char* name,
|
||||
InputDevice::AbsoluteAxisInfo* out);
|
||||
void configureExcludedDevices();
|
||||
|
||||
// global meta state management for all devices
|
||||
void resetGlobalMetaState();
|
||||
int32_t globalMetaState();
|
||||
|
||||
// virtual key management
|
||||
void updateGlobalVirtualKeyState();
|
||||
void updateExportedVirtualKeyState();
|
||||
|
||||
// input configuration management
|
||||
void updateExportedInputConfiguration();
|
||||
};
|
||||
|
||||
|
||||
|
@ -19,6 +19,9 @@
|
||||
// Log debug messages about the dispatch cycle.
|
||||
#define DEBUG_DISPATCH_CYCLE 1
|
||||
|
||||
// Log debug messages about registrations.
|
||||
#define DEBUG_REGISTRATION 1
|
||||
|
||||
// Log debug messages about performance statistics.
|
||||
#define DEBUG_PERFORMANCE_STATISTICS 1
|
||||
|
||||
@ -42,7 +45,7 @@ static inline bool isMovementKey(int32_t keyCode) {
|
||||
|
||||
// --- InputDispatcher ---
|
||||
|
||||
InputDispatcher::InputDispatcher(const sp<InputDispatchPolicyInterface>& policy) :
|
||||
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
|
||||
mPolicy(policy) {
|
||||
mPollLoop = new PollLoop();
|
||||
|
||||
@ -55,6 +58,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatchPolicyInterface>& policy)
|
||||
mInboundQueue.tail.eventTime = LONG_LONG_MAX;
|
||||
|
||||
mKeyRepeatState.lastKeyEntry = NULL;
|
||||
|
||||
mCurrentInputTargetsValid = false;
|
||||
}
|
||||
|
||||
InputDispatcher::~InputDispatcher() {
|
||||
@ -72,8 +77,9 @@ InputDispatcher::~InputDispatcher() {
|
||||
}
|
||||
|
||||
void InputDispatcher::dispatchOnce() {
|
||||
bool allowKeyRepeat = mPolicy->allowKeyRepeat();
|
||||
nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
|
||||
|
||||
bool skipPoll = false;
|
||||
nsecs_t currentTime;
|
||||
nsecs_t nextWakeupTime = LONG_LONG_MAX;
|
||||
{ // acquire lock
|
||||
@ -84,7 +90,7 @@ void InputDispatcher::dispatchOnce() {
|
||||
// is not a key. This is to ensure that we abort a key repeat if the device is just coming
|
||||
// out of sleep.
|
||||
// XXX we should handle resetting input state coming out of sleep more generally elsewhere
|
||||
if (! allowKeyRepeat) {
|
||||
if (keyRepeatTimeout < 0) {
|
||||
resetKeyRepeatLocked();
|
||||
}
|
||||
|
||||
@ -121,8 +127,8 @@ void InputDispatcher::dispatchOnce() {
|
||||
if (mInboundQueue.isEmpty()) {
|
||||
if (mKeyRepeatState.lastKeyEntry) {
|
||||
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
|
||||
processKeyRepeatLocked(currentTime);
|
||||
return; // dispatched once
|
||||
processKeyRepeatLockedInterruptible(currentTime, keyRepeatTimeout);
|
||||
skipPoll = true;
|
||||
} else {
|
||||
if (mKeyRepeatState.nextRepeatTime < nextWakeupTime) {
|
||||
nextWakeupTime = mKeyRepeatState.nextRepeatTime;
|
||||
@ -130,31 +136,30 @@ void InputDispatcher::dispatchOnce() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Inbound queue has at least one entry. Dequeue it and begin dispatching.
|
||||
// Note that we do not hold the lock for this process because dispatching may
|
||||
// involve making many callbacks.
|
||||
EventEntry* entry = mInboundQueue.dequeueAtHead();
|
||||
// Inbound queue has at least one entry.
|
||||
// Start processing it but leave it on the queue until later so that the
|
||||
// input reader can keep appending samples onto a motion event between the
|
||||
// time we started processing it and the time we finally enqueue dispatch
|
||||
// entries for it.
|
||||
EventEntry* entry = mInboundQueue.head.next;
|
||||
|
||||
switch (entry->type) {
|
||||
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
|
||||
ConfigurationChangedEntry* typedEntry =
|
||||
static_cast<ConfigurationChangedEntry*>(entry);
|
||||
processConfigurationChangedLocked(currentTime, typedEntry);
|
||||
mAllocator.releaseConfigurationChangedEntry(typedEntry);
|
||||
processConfigurationChangedLockedInterruptible(currentTime, typedEntry);
|
||||
break;
|
||||
}
|
||||
|
||||
case EventEntry::TYPE_KEY: {
|
||||
KeyEntry* typedEntry = static_cast<KeyEntry*>(entry);
|
||||
processKeyLocked(currentTime, typedEntry);
|
||||
mAllocator.releaseKeyEntry(typedEntry);
|
||||
processKeyLockedInterruptible(currentTime, typedEntry, keyRepeatTimeout);
|
||||
break;
|
||||
}
|
||||
|
||||
case EventEntry::TYPE_MOTION: {
|
||||
MotionEntry* typedEntry = static_cast<MotionEntry*>(entry);
|
||||
processMotionLocked(currentTime, typedEntry);
|
||||
mAllocator.releaseMotionEntry(typedEntry);
|
||||
processMotionLockedInterruptible(currentTime, typedEntry);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -162,30 +167,67 @@ void InputDispatcher::dispatchOnce() {
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return; // dispatched once
|
||||
|
||||
// Dequeue and release the event entry that we just processed.
|
||||
mInboundQueue.dequeue(entry);
|
||||
mAllocator.releaseEventEntry(entry);
|
||||
skipPoll = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Run any deferred commands.
|
||||
skipPoll |= runCommandsLockedInterruptible();
|
||||
} // release lock
|
||||
|
||||
// If we dispatched anything, don't poll just now. Wait for the next iteration.
|
||||
// Contents may have shifted during flight.
|
||||
if (skipPoll) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for callback or timeout or wake.
|
||||
nsecs_t timeout = nanoseconds_to_milliseconds(nextWakeupTime - currentTime);
|
||||
int32_t timeoutMillis = timeout > INT_MAX ? -1 : timeout > 0 ? int32_t(timeout) : 0;
|
||||
mPollLoop->pollOnce(timeoutMillis);
|
||||
}
|
||||
|
||||
void InputDispatcher::processConfigurationChangedLocked(nsecs_t currentTime,
|
||||
ConfigurationChangedEntry* entry) {
|
||||
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||
LOGD("processConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, "
|
||||
"keyboardConfig=%d, navigationConfig=%d", entry->eventTime,
|
||||
entry->touchScreenConfig, entry->keyboardConfig, entry->navigationConfig);
|
||||
#endif
|
||||
bool InputDispatcher::runCommandsLockedInterruptible() {
|
||||
if (mCommandQueue.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mPolicy->notifyConfigurationChanged(entry->eventTime, entry->touchScreenConfig,
|
||||
entry->keyboardConfig, entry->navigationConfig);
|
||||
do {
|
||||
CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
|
||||
|
||||
Command command = commandEntry->command;
|
||||
(this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
|
||||
|
||||
mAllocator.releaseCommandEntry(commandEntry);
|
||||
} while (! mCommandQueue.isEmpty());
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) {
|
||||
InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
|
||||
CommandEntry* commandEntry = mAllocator.obtainCommandEntry(command);
|
||||
mCommandQueue.enqueueAtTail(commandEntry);
|
||||
return commandEntry;
|
||||
}
|
||||
|
||||
void InputDispatcher::processConfigurationChangedLockedInterruptible(
|
||||
nsecs_t currentTime, ConfigurationChangedEntry* entry) {
|
||||
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||
LOGD("processConfigurationChanged - eventTime=%lld", entry->eventTime);
|
||||
#endif
|
||||
|
||||
mLock.unlock();
|
||||
|
||||
mPolicy->notifyConfigurationChanged(entry->eventTime);
|
||||
|
||||
mLock.lock();
|
||||
}
|
||||
|
||||
void InputDispatcher::processKeyLockedInterruptible(
|
||||
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout) {
|
||||
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||
LOGD("processKey - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
|
||||
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
|
||||
@ -209,7 +251,7 @@ void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) {
|
||||
} else {
|
||||
// Not a repeat. Save key down state in case we do see a repeat later.
|
||||
resetKeyRepeatLocked();
|
||||
mKeyRepeatState.nextRepeatTime = entry->eventTime + mPolicy->getKeyRepeatTimeout();
|
||||
mKeyRepeatState.nextRepeatTime = entry->eventTime + keyRepeatTimeout;
|
||||
}
|
||||
mKeyRepeatState.lastKeyEntry = entry;
|
||||
entry->refCount += 1;
|
||||
@ -217,10 +259,11 @@ void InputDispatcher::processKeyLocked(nsecs_t currentTime, KeyEntry* entry) {
|
||||
resetKeyRepeatLocked();
|
||||
}
|
||||
|
||||
identifyInputTargetsAndDispatchKeyLocked(currentTime, entry);
|
||||
identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry);
|
||||
}
|
||||
|
||||
void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) {
|
||||
void InputDispatcher::processKeyRepeatLockedInterruptible(
|
||||
nsecs_t currentTime, nsecs_t keyRepeatTimeout) {
|
||||
// TODO Old WindowManagerServer code sniffs the input queue for following key up
|
||||
// events and drops the repeat if one is found. We should do something similar.
|
||||
// One good place to do it is in notifyKey as soon as the key up enters the
|
||||
@ -252,7 +295,7 @@ void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) {
|
||||
entry->downTime = currentTime;
|
||||
entry->policyFlags = 0;
|
||||
|
||||
mKeyRepeatState.nextRepeatTime = currentTime + mPolicy->getKeyRepeatTimeout();
|
||||
mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;
|
||||
|
||||
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||
LOGD("processKeyRepeat - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, "
|
||||
@ -263,10 +306,11 @@ void InputDispatcher::processKeyRepeatLocked(nsecs_t currentTime) {
|
||||
entry->repeatCount, entry->downTime);
|
||||
#endif
|
||||
|
||||
identifyInputTargetsAndDispatchKeyLocked(currentTime, entry);
|
||||
identifyInputTargetsAndDispatchKeyLockedInterruptible(currentTime, entry);
|
||||
}
|
||||
|
||||
void InputDispatcher::processMotionLocked(nsecs_t currentTime, MotionEntry* entry) {
|
||||
void InputDispatcher::processMotionLockedInterruptible(
|
||||
nsecs_t currentTime, MotionEntry* entry) {
|
||||
#if DEBUG_OUTBOUND_EVENT_DETAILS
|
||||
LOGD("processMotion - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
|
||||
"metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
|
||||
@ -296,15 +340,19 @@ void InputDispatcher::processMotionLocked(nsecs_t currentTime, MotionEntry* entr
|
||||
}
|
||||
#endif
|
||||
|
||||
identifyInputTargetsAndDispatchMotionLocked(currentTime, entry);
|
||||
identifyInputTargetsAndDispatchMotionLockedInterruptible(currentTime, entry);
|
||||
}
|
||||
|
||||
void InputDispatcher::identifyInputTargetsAndDispatchKeyLocked(
|
||||
void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible(
|
||||
nsecs_t currentTime, KeyEntry* entry) {
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("identifyInputTargetsAndDispatchKey");
|
||||
#endif
|
||||
|
||||
entry->dispatchInProgress = true;
|
||||
mCurrentInputTargetsValid = false;
|
||||
mLock.unlock();
|
||||
|
||||
mReusableKeyEvent.initialize(entry->deviceId, entry->nature, entry->action, entry->flags,
|
||||
entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
|
||||
entry->downTime, entry->eventTime);
|
||||
@ -313,15 +361,22 @@ void InputDispatcher::identifyInputTargetsAndDispatchKeyLocked(
|
||||
mPolicy->getKeyEventTargets(& mReusableKeyEvent, entry->policyFlags,
|
||||
mCurrentInputTargets);
|
||||
|
||||
mLock.lock();
|
||||
mCurrentInputTargetsValid = true;
|
||||
|
||||
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
|
||||
}
|
||||
|
||||
void InputDispatcher::identifyInputTargetsAndDispatchMotionLocked(
|
||||
void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
|
||||
nsecs_t currentTime, MotionEntry* entry) {
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("identifyInputTargetsAndDispatchMotion");
|
||||
#endif
|
||||
|
||||
entry->dispatchInProgress = true;
|
||||
mCurrentInputTargetsValid = false;
|
||||
mLock.unlock();
|
||||
|
||||
mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action,
|
||||
entry->edgeFlags, entry->metaState,
|
||||
entry->firstSample.pointerCoords[0].x, entry->firstSample.pointerCoords[0].y,
|
||||
@ -333,17 +388,22 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLocked(
|
||||
mPolicy->getMotionEventTargets(& mReusableMotionEvent, entry->policyFlags,
|
||||
mCurrentInputTargets);
|
||||
|
||||
mLock.lock();
|
||||
mCurrentInputTargetsValid = true;
|
||||
|
||||
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
|
||||
}
|
||||
|
||||
void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
|
||||
EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("dispatchEventToCurrentInputTargets, "
|
||||
LOGD("dispatchEventToCurrentInputTargets - "
|
||||
"resumeWithAppendedMotionSample=%s",
|
||||
resumeWithAppendedMotionSample ? "true" : "false");
|
||||
#endif
|
||||
|
||||
assert(eventEntry->dispatchInProgress); // should already have been set to true
|
||||
|
||||
for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
|
||||
const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
|
||||
|
||||
@ -365,7 +425,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, Connection
|
||||
EventEntry* eventEntry, const InputTarget* inputTarget,
|
||||
bool resumeWithAppendedMotionSample) {
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("channel '%s' ~ prepareDispatchCycle, flags=%d, timeout=%lldns, "
|
||||
LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, timeout=%lldns, "
|
||||
"xOffset=%f, yOffset=%f, resumeWithAppendedMotionSample=%s",
|
||||
connection->getInputChannelName(), inputTarget->flags, inputTarget->timeout,
|
||||
inputTarget->xOffset, inputTarget->yOffset,
|
||||
@ -377,7 +437,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, Connection
|
||||
// not responding.
|
||||
if (connection->status != Connection::STATUS_NORMAL) {
|
||||
LOGV("channel '%s' ~ Dropping event because the channel status is %s",
|
||||
connection->status == Connection::STATUS_BROKEN ? "BROKEN" : "NOT RESPONDING");
|
||||
connection->getStatusLabel());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -631,14 +691,15 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, Connection*
|
||||
|
||||
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, Connection* connection) {
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("channel '%s' ~ finishDispatchCycle: %01.1fms since event, "
|
||||
LOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
|
||||
"%01.1fms since dispatch",
|
||||
connection->getInputChannelName(),
|
||||
connection->getEventLatencyMillis(currentTime),
|
||||
connection->getDispatchLatencyMillis(currentTime));
|
||||
#endif
|
||||
|
||||
if (connection->status == Connection::STATUS_BROKEN) {
|
||||
if (connection->status == Connection::STATUS_BROKEN
|
||||
|| connection->status == Connection::STATUS_ZOMBIE) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -722,34 +783,37 @@ bool InputDispatcher::timeoutDispatchCycleLocked(nsecs_t currentTime, Connection
|
||||
bool InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
|
||||
bool broken) {
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("channel '%s' ~ abortDispatchCycle, broken=%s",
|
||||
LOGD("channel '%s' ~ abortDispatchCycle - broken=%s",
|
||||
connection->getInputChannelName(), broken ? "true" : "false");
|
||||
#endif
|
||||
|
||||
if (connection->status == Connection::STATUS_BROKEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear the pending timeout.
|
||||
connection->nextTimeoutTime = LONG_LONG_MAX;
|
||||
|
||||
// Clear the outbound queue.
|
||||
while (! connection->outboundQueue.isEmpty()) {
|
||||
DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
|
||||
mAllocator.releaseDispatchEntry(dispatchEntry);
|
||||
}
|
||||
bool deactivated = ! connection->outboundQueue.isEmpty();
|
||||
if (deactivated) {
|
||||
do {
|
||||
DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
|
||||
mAllocator.releaseDispatchEntry(dispatchEntry);
|
||||
} while (! connection->outboundQueue.isEmpty());
|
||||
|
||||
// Outbound queue is empty, deactivate the connection.
|
||||
deactivateConnectionLocked(connection);
|
||||
deactivateConnectionLocked(connection);
|
||||
}
|
||||
|
||||
// Handle the case where the connection appears to be unrecoverably broken.
|
||||
// Ignore already broken or zombie connections.
|
||||
if (broken) {
|
||||
connection->status = Connection::STATUS_BROKEN;
|
||||
if (connection->status == Connection::STATUS_NORMAL
|
||||
|| connection->status == Connection::STATUS_NOT_RESPONDING) {
|
||||
connection->status = Connection::STATUS_BROKEN;
|
||||
|
||||
// Notify other system components.
|
||||
onDispatchCycleBrokenLocked(currentTime, connection);
|
||||
// Notify other system components.
|
||||
onDispatchCycleBrokenLocked(currentTime, connection);
|
||||
}
|
||||
}
|
||||
return true; /*deactivated*/
|
||||
|
||||
return deactivated;
|
||||
}
|
||||
|
||||
bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
|
||||
@ -772,6 +836,7 @@ bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* dat
|
||||
LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. "
|
||||
"events=0x%x", connection->getInputChannelName(), events);
|
||||
d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
|
||||
d->runCommandsLockedInterruptible();
|
||||
return false; // remove the callback
|
||||
}
|
||||
|
||||
@ -786,20 +851,19 @@ bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* dat
|
||||
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
|
||||
connection->getInputChannelName(), status);
|
||||
d->abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
|
||||
d->runCommandsLockedInterruptible();
|
||||
return false; // remove the callback
|
||||
}
|
||||
|
||||
d->finishDispatchCycleLocked(currentTime, connection.get());
|
||||
d->runCommandsLockedInterruptible();
|
||||
return true;
|
||||
} // release lock
|
||||
}
|
||||
|
||||
void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touchScreenConfig,
|
||||
int32_t keyboardConfig, int32_t navigationConfig) {
|
||||
void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime) {
|
||||
#if DEBUG_INBOUND_EVENT_DETAILS
|
||||
LOGD("notifyConfigurationChanged - eventTime=%lld, touchScreenConfig=%d, "
|
||||
"keyboardConfig=%d, navigationConfig=%d", eventTime,
|
||||
touchScreenConfig, keyboardConfig, navigationConfig);
|
||||
LOGD("notifyConfigurationChanged - eventTime=%lld", eventTime);
|
||||
#endif
|
||||
|
||||
bool wasEmpty;
|
||||
@ -808,9 +872,6 @@ void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touc
|
||||
|
||||
ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry();
|
||||
newEntry->eventTime = eventTime;
|
||||
newEntry->touchScreenConfig = touchScreenConfig;
|
||||
newEntry->keyboardConfig = keyboardConfig;
|
||||
newEntry->navigationConfig = navigationConfig;
|
||||
|
||||
wasEmpty = mInboundQueue.isEmpty();
|
||||
mInboundQueue.enqueueAtTail(newEntry);
|
||||
@ -821,16 +882,6 @@ void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime, int32_t touc
|
||||
}
|
||||
}
|
||||
|
||||
void InputDispatcher::notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) {
|
||||
#if DEBUG_INBOUND_EVENT_DETAILS
|
||||
LOGD("notifyLidSwitchChanged - eventTime=%lld, open=%s", eventTime,
|
||||
lidOpen ? "true" : "false");
|
||||
#endif
|
||||
|
||||
// Send lid switch notification immediately and synchronously.
|
||||
mPolicy->notifyLidSwitchChanged(eventTime, lidOpen);
|
||||
}
|
||||
|
||||
void InputDispatcher::notifyAppSwitchComing(nsecs_t eventTime) {
|
||||
#if DEBUG_INBOUND_EVENT_DETAILS
|
||||
LOGD("notifyAppSwitchComing - eventTime=%lld", eventTime);
|
||||
@ -949,13 +1000,25 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t
|
||||
}
|
||||
|
||||
// The last motion event is a move and is compatible for appending.
|
||||
// Do the batching magic and exit.
|
||||
// Do the batching magic.
|
||||
mAllocator.appendMotionSample(motionEntry, eventTime, pointerCount, pointerCoords);
|
||||
#if DEBUG_BATCHING
|
||||
LOGD("Appended motion sample onto batch for most recent "
|
||||
"motion event for this device in the inbound queue.");
|
||||
#endif
|
||||
return; // done
|
||||
|
||||
// Sanity check for special case because dispatch is interruptible.
|
||||
// The dispatch logic is partially interruptible and releases its lock while
|
||||
// identifying targets. However, as soon as the targets have been identified,
|
||||
// the dispatcher proceeds to write a dispatch entry into all relevant outbound
|
||||
// queues and then promptly removes the motion entry from the queue.
|
||||
//
|
||||
// Consequently, we should never observe the case where the inbound queue contains
|
||||
// an in-progress motion entry unless the current input targets are invalid
|
||||
// (currently being computed). Check for this!
|
||||
assert(! (motionEntry->dispatchInProgress && mCurrentInputTargetsValid));
|
||||
|
||||
return; // done!
|
||||
}
|
||||
|
||||
// STREAMING CASE
|
||||
@ -977,34 +1040,38 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t
|
||||
// Note: This code crucially depends on the invariant that an outbound queue always
|
||||
// contains at most one synchronous event and it is always last (but it might
|
||||
// not be first!).
|
||||
for (size_t i = 0; i < mActiveConnections.size(); i++) {
|
||||
Connection* connection = mActiveConnections.itemAt(i);
|
||||
if (! connection->outboundQueue.isEmpty()) {
|
||||
DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev;
|
||||
if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) {
|
||||
if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
|
||||
goto NoBatchingOrStreaming;
|
||||
}
|
||||
if (mCurrentInputTargetsValid) {
|
||||
for (size_t i = 0; i < mActiveConnections.size(); i++) {
|
||||
Connection* connection = mActiveConnections.itemAt(i);
|
||||
if (! connection->outboundQueue.isEmpty()) {
|
||||
DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev;
|
||||
if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) {
|
||||
if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
|
||||
goto NoBatchingOrStreaming;
|
||||
}
|
||||
|
||||
MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>(
|
||||
dispatchEntry->eventEntry);
|
||||
if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE
|
||||
|| syncedMotionEntry->deviceId != deviceId
|
||||
|| syncedMotionEntry->pointerCount != pointerCount) {
|
||||
goto NoBatchingOrStreaming;
|
||||
}
|
||||
MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>(
|
||||
dispatchEntry->eventEntry);
|
||||
if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE
|
||||
|| syncedMotionEntry->deviceId != deviceId
|
||||
|| syncedMotionEntry->pointerCount != pointerCount) {
|
||||
goto NoBatchingOrStreaming;
|
||||
}
|
||||
|
||||
// Found synced move entry. Append sample and resume dispatch.
|
||||
mAllocator.appendMotionSample(syncedMotionEntry, eventTime,
|
||||
pointerCount, pointerCoords);
|
||||
#if DEBUG_BATCHING
|
||||
LOGD("Appended motion sample onto batch for most recent synchronously "
|
||||
"dispatched motion event for this device in the outbound queues.");
|
||||
#endif
|
||||
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry,
|
||||
true /*resumeWithAppendedMotionSample*/);
|
||||
return; // done!
|
||||
// Found synced move entry. Append sample and resume dispatch.
|
||||
mAllocator.appendMotionSample(syncedMotionEntry, eventTime,
|
||||
pointerCount, pointerCoords);
|
||||
#if DEBUG_BATCHING
|
||||
LOGD("Appended motion sample onto batch for most recent synchronously "
|
||||
"dispatched motion event for this device in the outbound queues.");
|
||||
#endif
|
||||
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
dispatchEventToCurrentInputTargetsLocked(currentTime, syncedMotionEntry,
|
||||
true /*resumeWithAppendedMotionSample*/);
|
||||
|
||||
runCommandsLockedInterruptible();
|
||||
return; // done!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1049,6 +1116,10 @@ void InputDispatcher::resetKeyRepeatLocked() {
|
||||
}
|
||||
|
||||
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
|
||||
#if DEBUG_REGISTRATION
|
||||
LOGD("channel '%s' - Registered", inputChannel->getName().string());
|
||||
#endif
|
||||
|
||||
int receiveFd;
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
@ -1069,6 +1140,8 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan
|
||||
}
|
||||
|
||||
mConnectionsByReceiveFd.add(receiveFd, connection);
|
||||
|
||||
runCommandsLockedInterruptible();
|
||||
} // release lock
|
||||
|
||||
mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
|
||||
@ -1076,6 +1149,10 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan
|
||||
}
|
||||
|
||||
status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
|
||||
#if DEBUG_REGISTRATION
|
||||
LOGD("channel '%s' - Unregistered", inputChannel->getName().string());
|
||||
#endif
|
||||
|
||||
int32_t receiveFd;
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
@ -1095,6 +1172,8 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh
|
||||
|
||||
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
abortDispatchCycleLocked(currentTime, connection.get(), true /*broken*/);
|
||||
|
||||
runCommandsLockedInterruptible();
|
||||
} // release lock
|
||||
|
||||
mPollLoop->removeCallback(receiveFd);
|
||||
@ -1123,11 +1202,12 @@ void InputDispatcher::deactivateConnectionLocked(Connection* connection) {
|
||||
}
|
||||
}
|
||||
|
||||
void InputDispatcher::onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection) {
|
||||
void InputDispatcher::onDispatchCycleStartedLocked(
|
||||
nsecs_t currentTime, Connection* connection) {
|
||||
}
|
||||
|
||||
void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
|
||||
Connection* connection, bool recoveredFromANR) {
|
||||
void InputDispatcher::onDispatchCycleFinishedLocked(
|
||||
nsecs_t currentTime, Connection* connection, bool recoveredFromANR) {
|
||||
if (recoveredFromANR) {
|
||||
LOGI("channel '%s' ~ Recovered from ANR. %01.1fms since event, "
|
||||
"%01.1fms since dispatch, %01.1fms since ANR",
|
||||
@ -1136,26 +1216,65 @@ void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
|
||||
connection->getDispatchLatencyMillis(currentTime),
|
||||
connection->getANRLatencyMillis(currentTime));
|
||||
|
||||
// TODO tell framework
|
||||
CommandEntry* commandEntry = postCommandLocked(
|
||||
& InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible);
|
||||
commandEntry->inputChannel = connection->inputChannel;
|
||||
}
|
||||
}
|
||||
|
||||
void InputDispatcher::onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection) {
|
||||
void InputDispatcher::onDispatchCycleANRLocked(
|
||||
nsecs_t currentTime, Connection* connection) {
|
||||
LOGI("channel '%s' ~ Not responding! %01.1fms since event, %01.1fms since dispatch",
|
||||
connection->getInputChannelName(),
|
||||
connection->getEventLatencyMillis(currentTime),
|
||||
connection->getDispatchLatencyMillis(currentTime));
|
||||
|
||||
// TODO tell framework
|
||||
CommandEntry* commandEntry = postCommandLocked(
|
||||
& InputDispatcher::doNotifyInputChannelANRLockedInterruptible);
|
||||
commandEntry->inputChannel = connection->inputChannel;
|
||||
}
|
||||
|
||||
void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection) {
|
||||
void InputDispatcher::onDispatchCycleBrokenLocked(
|
||||
nsecs_t currentTime, Connection* connection) {
|
||||
LOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
|
||||
connection->getInputChannelName());
|
||||
|
||||
// TODO tell framework
|
||||
CommandEntry* commandEntry = postCommandLocked(
|
||||
& InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
|
||||
commandEntry->inputChannel = connection->inputChannel;
|
||||
}
|
||||
|
||||
void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(
|
||||
CommandEntry* commandEntry) {
|
||||
mLock.unlock();
|
||||
|
||||
mPolicy->notifyInputChannelBroken(commandEntry->inputChannel);
|
||||
commandEntry->inputChannel.clear();
|
||||
|
||||
mLock.lock();
|
||||
}
|
||||
|
||||
void InputDispatcher::doNotifyInputChannelANRLockedInterruptible(
|
||||
CommandEntry* commandEntry) {
|
||||
mLock.unlock();
|
||||
|
||||
mPolicy->notifyInputChannelANR(commandEntry->inputChannel);
|
||||
commandEntry->inputChannel.clear();
|
||||
|
||||
mLock.lock();
|
||||
}
|
||||
|
||||
void InputDispatcher::doNotifyInputChannelRecoveredFromANRLockedInterruptible(
|
||||
CommandEntry* commandEntry) {
|
||||
mLock.unlock();
|
||||
|
||||
mPolicy->notifyInputChannelRecoveredFromANR(commandEntry->inputChannel);
|
||||
commandEntry->inputChannel.clear();
|
||||
|
||||
mLock.lock();
|
||||
}
|
||||
|
||||
|
||||
// --- InputDispatcher::Allocator ---
|
||||
|
||||
InputDispatcher::Allocator::Allocator() {
|
||||
@ -1166,6 +1285,7 @@ InputDispatcher::Allocator::obtainConfigurationChangedEntry() {
|
||||
ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc();
|
||||
entry->refCount = 1;
|
||||
entry->type = EventEntry::TYPE_CONFIGURATION_CHANGED;
|
||||
entry->dispatchInProgress = false;
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -1173,6 +1293,7 @@ InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry() {
|
||||
KeyEntry* entry = mKeyEntryPool.alloc();
|
||||
entry->refCount = 1;
|
||||
entry->type = EventEntry::TYPE_KEY;
|
||||
entry->dispatchInProgress = false;
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -1181,6 +1302,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry() {
|
||||
entry->refCount = 1;
|
||||
entry->type = EventEntry::TYPE_MOTION;
|
||||
entry->firstSample.next = NULL;
|
||||
entry->dispatchInProgress = false;
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -1192,6 +1314,12 @@ InputDispatcher::DispatchEntry* InputDispatcher::Allocator::obtainDispatchEntry(
|
||||
return entry;
|
||||
}
|
||||
|
||||
InputDispatcher::CommandEntry* InputDispatcher::Allocator::obtainCommandEntry(Command command) {
|
||||
CommandEntry* entry = mCommandEntryPool.alloc();
|
||||
entry->command = command;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void InputDispatcher::Allocator::releaseEventEntry(EventEntry* entry) {
|
||||
switch (entry->type) {
|
||||
case EventEntry::TYPE_CONFIGURATION_CHANGED:
|
||||
@ -1231,7 +1359,11 @@ void InputDispatcher::Allocator::releaseKeyEntry(KeyEntry* entry) {
|
||||
void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) {
|
||||
entry->refCount -= 1;
|
||||
if (entry->refCount == 0) {
|
||||
freeMotionSampleList(entry->firstSample.next);
|
||||
for (MotionSample* sample = entry->firstSample.next; sample != NULL; ) {
|
||||
MotionSample* next = sample->next;
|
||||
mMotionSamplePool.free(sample);
|
||||
sample = next;
|
||||
}
|
||||
mMotionEntryPool.free(entry);
|
||||
} else {
|
||||
assert(entry->refCount > 0);
|
||||
@ -1243,6 +1375,10 @@ void InputDispatcher::Allocator::releaseDispatchEntry(DispatchEntry* entry) {
|
||||
mDispatchEntryPool.free(entry);
|
||||
}
|
||||
|
||||
void InputDispatcher::Allocator::releaseCommandEntry(CommandEntry* entry) {
|
||||
mCommandEntryPool.free(entry);
|
||||
}
|
||||
|
||||
void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,
|
||||
nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords) {
|
||||
MotionSample* sample = mMotionSamplePool.alloc();
|
||||
@ -1256,18 +1392,6 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,
|
||||
motionEntry->lastSample = sample;
|
||||
}
|
||||
|
||||
void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) {
|
||||
mMotionSamplePool.free(sample);
|
||||
}
|
||||
|
||||
void InputDispatcher::Allocator::freeMotionSampleList(MotionSample* head) {
|
||||
while (head) {
|
||||
MotionSample* next = head->next;
|
||||
mMotionSamplePool.free(head);
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
|
||||
// --- InputDispatcher::Connection ---
|
||||
|
||||
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel) :
|
||||
@ -1284,6 +1408,25 @@ status_t InputDispatcher::Connection::initialize() {
|
||||
return inputPublisher.initialize();
|
||||
}
|
||||
|
||||
const char* InputDispatcher::Connection::getStatusLabel() const {
|
||||
switch (status) {
|
||||
case STATUS_NORMAL:
|
||||
return "NORMAL";
|
||||
|
||||
case STATUS_BROKEN:
|
||||
return "BROKEN";
|
||||
|
||||
case STATUS_NOT_RESPONDING:
|
||||
return "NOT_RESPONDING";
|
||||
|
||||
case STATUS_ZOMBIE:
|
||||
return "ZOMBIE";
|
||||
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent(
|
||||
const EventEntry* eventEntry) const {
|
||||
for (DispatchEntry* dispatchEntry = outboundQueue.tail.prev;
|
||||
@ -1295,6 +1438,14 @@ InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchE
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// --- InputDispatcher::CommandEntry ---
|
||||
|
||||
InputDispatcher::CommandEntry::CommandEntry() {
|
||||
}
|
||||
|
||||
InputDispatcher::CommandEntry::~CommandEntry() {
|
||||
}
|
||||
|
||||
|
||||
// --- InputDispatcherThread ---
|
||||
|
||||
|
@ -14,29 +14,30 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
InputManager::InputManager(const sp<EventHubInterface>& eventHub,
|
||||
const sp<InputDispatchPolicyInterface>& policy) :
|
||||
mEventHub(eventHub), mPolicy(policy) {
|
||||
mDispatcher = new InputDispatcher(policy);
|
||||
mReader = new InputReader(eventHub, policy, mDispatcher);
|
||||
InputManager::InputManager(
|
||||
const sp<EventHubInterface>& eventHub,
|
||||
const sp<InputReaderPolicyInterface>& readerPolicy,
|
||||
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
|
||||
mDispatcher = new InputDispatcher(dispatcherPolicy);
|
||||
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
|
||||
initialize();
|
||||
}
|
||||
|
||||
mDispatcherThread = new InputDispatcherThread(mDispatcher);
|
||||
mReaderThread = new InputReaderThread(mReader);
|
||||
|
||||
configureExcludedDevices();
|
||||
InputManager::InputManager(
|
||||
const sp<InputReaderInterface>& reader,
|
||||
const sp<InputDispatcherInterface>& dispatcher) :
|
||||
mReader(reader),
|
||||
mDispatcher(dispatcher) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
InputManager::~InputManager() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void InputManager::configureExcludedDevices() {
|
||||
Vector<String8> excludedDeviceNames;
|
||||
mPolicy->getExcludedDeviceNames(excludedDeviceNames);
|
||||
|
||||
for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
|
||||
mEventHub->addExcludedDevice(excludedDeviceNames[i]);
|
||||
}
|
||||
void InputManager::initialize() {
|
||||
mReaderThread = new InputReaderThread(mReader);
|
||||
mDispatcherThread = new InputDispatcherThread(mDispatcher);
|
||||
}
|
||||
|
||||
status_t InputManager::start() {
|
||||
@ -79,36 +80,26 @@ status_t InputManager::unregisterInputChannel(const sp<InputChannel>& inputChann
|
||||
return mDispatcher->unregisterInputChannel(inputChannel);
|
||||
}
|
||||
|
||||
int32_t InputManager::getScanCodeState(int32_t deviceId, int32_t deviceClasses, int32_t scanCode)
|
||||
const {
|
||||
int32_t vkKeyCode, vkScanCode;
|
||||
if (mReader->getCurrentVirtualKey(& vkKeyCode, & vkScanCode)) {
|
||||
if (vkScanCode == scanCode) {
|
||||
return KEY_STATE_VIRTUAL;
|
||||
}
|
||||
}
|
||||
|
||||
return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode);
|
||||
void InputManager::getInputConfiguration(InputConfiguration* outConfiguration) const {
|
||||
mReader->getCurrentInputConfiguration(outConfiguration);
|
||||
}
|
||||
|
||||
int32_t InputManager::getKeyCodeState(int32_t deviceId, int32_t deviceClasses, int32_t keyCode)
|
||||
const {
|
||||
int32_t vkKeyCode, vkScanCode;
|
||||
if (mReader->getCurrentVirtualKey(& vkKeyCode, & vkScanCode)) {
|
||||
if (vkKeyCode == keyCode) {
|
||||
return KEY_STATE_VIRTUAL;
|
||||
}
|
||||
}
|
||||
int32_t InputManager::getScanCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t scanCode) const {
|
||||
return mReader->getCurrentScanCodeState(deviceId, deviceClasses, scanCode);
|
||||
}
|
||||
|
||||
return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode);
|
||||
int32_t InputManager::getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t keyCode) const {
|
||||
return mReader->getCurrentKeyCodeState(deviceId, deviceClasses, keyCode);
|
||||
}
|
||||
|
||||
int32_t InputManager::getSwitchState(int32_t deviceId, int32_t deviceClasses, int32_t sw) const {
|
||||
return mEventHub->getSwitchState(deviceId, deviceClasses, sw);
|
||||
return mReader->getCurrentSwitchState(deviceId, deviceClasses, sw);
|
||||
}
|
||||
|
||||
bool InputManager::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
|
||||
return mEventHub->hasKeys(numCodes, keyCodes, outFlags);
|
||||
return mReader->hasKeys(numCodes, keyCodes, outFlags);
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
@ -27,6 +27,22 @@
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
/** Amount that trackball needs to move in order to generate a key event. */
|
||||
#define TRACKBALL_MOVEMENT_THRESHOLD 6
|
||||
|
||||
/* Slop distance for jumpy pointer detection.
|
||||
* The vertical range of the screen divided by this is our epsilon value. */
|
||||
#define JUMPY_EPSILON_DIVISOR 212
|
||||
|
||||
/* Number of jumpy points to drop for touchscreens that need it. */
|
||||
#define JUMPY_TRANSITION_DROPS 3
|
||||
#define JUMPY_DROP_LIMIT 3
|
||||
|
||||
/* Maximum squared distance for averaging.
|
||||
* If moving farther than this, turn of averaging to avoid lag in response. */
|
||||
#define AVERAGING_DISTANCE_LIMIT (75 * 75)
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- Static Functions ---
|
||||
@ -89,7 +105,7 @@ static const int keyCodeRotationMapSize =
|
||||
sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
|
||||
|
||||
int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
|
||||
if (orientation != InputDispatchPolicyInterface::ROTATION_0) {
|
||||
if (orientation != InputReaderPolicyInterface::ROTATION_0) {
|
||||
for (int i = 0; i < keyCodeRotationMapSize; i++) {
|
||||
if (keyCode == keyCodeRotationMap[i][0]) {
|
||||
return keyCodeRotationMap[i][orientation];
|
||||
@ -677,12 +693,13 @@ void InputDevice::MultiTouchScreenState::reset() {
|
||||
// --- InputReader ---
|
||||
|
||||
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
|
||||
const sp<InputDispatchPolicyInterface>& policy,
|
||||
const sp<InputReaderPolicyInterface>& policy,
|
||||
const sp<InputDispatcherInterface>& dispatcher) :
|
||||
mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher) {
|
||||
configureExcludedDevices();
|
||||
resetGlobalMetaState();
|
||||
resetDisplayProperties();
|
||||
updateGlobalVirtualKeyState();
|
||||
updateExportedVirtualKeyState();
|
||||
}
|
||||
|
||||
InputReader::~InputReader() {
|
||||
@ -925,7 +942,7 @@ void InputReader::handleSwitch(const RawEvent* rawEvent) {
|
||||
InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
|
||||
if (! device) return;
|
||||
|
||||
onSwitch(rawEvent->when, device, rawEvent->value != 0, rawEvent->scanCode);
|
||||
onSwitch(rawEvent->when, device, rawEvent->scanCode, rawEvent->value);
|
||||
}
|
||||
|
||||
void InputReader::onKey(nsecs_t when, InputDevice* device,
|
||||
@ -974,7 +991,7 @@ void InputReader::onKey(nsecs_t when, InputDevice* device,
|
||||
}
|
||||
|
||||
int32_t keyEventFlags = KEY_EVENT_FLAG_FROM_SYSTEM;
|
||||
if (policyActions & InputDispatchPolicyInterface::ACTION_WOKE_HERE) {
|
||||
if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
|
||||
keyEventFlags = keyEventFlags | KEY_EVENT_FLAG_WOKE_HERE;
|
||||
}
|
||||
|
||||
@ -984,12 +1001,12 @@ void InputReader::onKey(nsecs_t when, InputDevice* device,
|
||||
device->keyboard.current.downTime);
|
||||
}
|
||||
|
||||
void InputReader::onSwitch(nsecs_t when, InputDevice* device, bool down,
|
||||
int32_t code) {
|
||||
switch (code) {
|
||||
case SW_LID:
|
||||
mDispatcher->notifyLidSwitchChanged(when, ! down);
|
||||
}
|
||||
void InputReader::onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode,
|
||||
int32_t switchValue) {
|
||||
int32_t policyActions = mPolicy->interceptSwitch(when, switchCode, switchValue);
|
||||
|
||||
uint32_t policyFlags = 0;
|
||||
applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags);
|
||||
}
|
||||
|
||||
void InputReader::onMultiTouchScreenStateChanged(nsecs_t when,
|
||||
@ -1256,7 +1273,7 @@ void InputReader::dispatchVirtualKey(nsecs_t when,
|
||||
nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
|
||||
int32_t metaState = globalMetaState();
|
||||
|
||||
updateGlobalVirtualKeyState();
|
||||
updateExportedVirtualKeyState();
|
||||
|
||||
mPolicy->virtualKeyFeedback(when, device->id, keyEventAction, keyEventFlags,
|
||||
keyCode, scanCode, metaState, downTime);
|
||||
@ -1333,8 +1350,8 @@ void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t poli
|
||||
int32_t motionEventAction) {
|
||||
int32_t orientedWidth, orientedHeight;
|
||||
switch (mDisplayOrientation) {
|
||||
case InputDispatchPolicyInterface::ROTATION_90:
|
||||
case InputDispatchPolicyInterface::ROTATION_270:
|
||||
case InputReaderPolicyInterface::ROTATION_90:
|
||||
case InputReaderPolicyInterface::ROTATION_270:
|
||||
orientedWidth = mDisplayHeight;
|
||||
orientedHeight = mDisplayWidth;
|
||||
break;
|
||||
@ -1369,18 +1386,18 @@ void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t poli
|
||||
* device->touchScreen.precalculated.sizeScale;
|
||||
|
||||
switch (mDisplayOrientation) {
|
||||
case InputDispatchPolicyInterface::ROTATION_90: {
|
||||
case InputReaderPolicyInterface::ROTATION_90: {
|
||||
float xTemp = x;
|
||||
x = y;
|
||||
y = mDisplayHeight - xTemp;
|
||||
break;
|
||||
}
|
||||
case InputDispatchPolicyInterface::ROTATION_180: {
|
||||
case InputReaderPolicyInterface::ROTATION_180: {
|
||||
x = mDisplayWidth - x;
|
||||
y = mDisplayHeight - y;
|
||||
break;
|
||||
}
|
||||
case InputDispatchPolicyInterface::ROTATION_270: {
|
||||
case InputReaderPolicyInterface::ROTATION_270: {
|
||||
float xTemp = x;
|
||||
x = mDisplayWidth - y;
|
||||
y = xTemp;
|
||||
@ -1483,18 +1500,18 @@ void InputReader::onTrackballStateChanged(nsecs_t when,
|
||||
|
||||
float temp;
|
||||
switch (mDisplayOrientation) {
|
||||
case InputDispatchPolicyInterface::ROTATION_90:
|
||||
case InputReaderPolicyInterface::ROTATION_90:
|
||||
temp = pointerCoords.x;
|
||||
pointerCoords.x = pointerCoords.y;
|
||||
pointerCoords.y = - temp;
|
||||
break;
|
||||
|
||||
case InputDispatchPolicyInterface::ROTATION_180:
|
||||
case InputReaderPolicyInterface::ROTATION_180:
|
||||
pointerCoords.x = - pointerCoords.x;
|
||||
pointerCoords.y = - pointerCoords.y;
|
||||
break;
|
||||
|
||||
case InputDispatchPolicyInterface::ROTATION_270:
|
||||
case InputReaderPolicyInterface::ROTATION_270:
|
||||
temp = pointerCoords.x;
|
||||
pointerCoords.x = - pointerCoords.y;
|
||||
pointerCoords.y = temp;
|
||||
@ -1514,51 +1531,30 @@ void InputReader::onConfigurationChanged(nsecs_t when) {
|
||||
resetGlobalMetaState();
|
||||
|
||||
// Reset virtual keys, just in case.
|
||||
updateGlobalVirtualKeyState();
|
||||
updateExportedVirtualKeyState();
|
||||
|
||||
// Update input configuration.
|
||||
updateExportedInputConfiguration();
|
||||
|
||||
// Enqueue configuration changed.
|
||||
// XXX This stuff probably needs to be tracked elsewhere in an input device registry
|
||||
// of some kind that can be asynchronously updated and queried. (Same as above?)
|
||||
int32_t touchScreenConfig = InputDispatchPolicyInterface::TOUCHSCREEN_NOTOUCH;
|
||||
int32_t keyboardConfig = InputDispatchPolicyInterface::KEYBOARD_NOKEYS;
|
||||
int32_t navigationConfig = InputDispatchPolicyInterface::NAVIGATION_NONAV;
|
||||
|
||||
for (size_t i = 0; i < mDevices.size(); i++) {
|
||||
InputDevice* device = mDevices.valueAt(i);
|
||||
int32_t deviceClasses = device->classes;
|
||||
|
||||
if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
|
||||
touchScreenConfig = InputDispatchPolicyInterface::TOUCHSCREEN_FINGER;
|
||||
}
|
||||
if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) {
|
||||
keyboardConfig = InputDispatchPolicyInterface::KEYBOARD_QWERTY;
|
||||
}
|
||||
if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) {
|
||||
navigationConfig = InputDispatchPolicyInterface::NAVIGATION_TRACKBALL;
|
||||
} else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) {
|
||||
navigationConfig = InputDispatchPolicyInterface::NAVIGATION_DPAD;
|
||||
}
|
||||
}
|
||||
|
||||
mDispatcher->notifyConfigurationChanged(when, touchScreenConfig,
|
||||
keyboardConfig, navigationConfig);
|
||||
mDispatcher->notifyConfigurationChanged(when);
|
||||
}
|
||||
|
||||
bool InputReader::applyStandardInputDispatchPolicyActions(nsecs_t when,
|
||||
int32_t policyActions, uint32_t* policyFlags) {
|
||||
if (policyActions & InputDispatchPolicyInterface::ACTION_APP_SWITCH_COMING) {
|
||||
if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) {
|
||||
mDispatcher->notifyAppSwitchComing(when);
|
||||
}
|
||||
|
||||
if (policyActions & InputDispatchPolicyInterface::ACTION_WOKE_HERE) {
|
||||
if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
|
||||
*policyFlags |= POLICY_FLAG_WOKE_HERE;
|
||||
}
|
||||
|
||||
if (policyActions & InputDispatchPolicyInterface::ACTION_BRIGHT_HERE) {
|
||||
if (policyActions & InputReaderPolicyInterface::ACTION_BRIGHT_HERE) {
|
||||
*policyFlags |= POLICY_FLAG_BRIGHT_HERE;
|
||||
}
|
||||
|
||||
return policyActions & InputDispatchPolicyInterface::ACTION_DISPATCH;
|
||||
return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
|
||||
}
|
||||
|
||||
void InputReader::resetDisplayProperties() {
|
||||
@ -1706,7 +1702,7 @@ void InputReader::configureDeviceForCurrentDisplaySize(InputDevice* device) {
|
||||
void InputReader::configureVirtualKeys(InputDevice* device) {
|
||||
device->touchScreen.virtualKeys.clear();
|
||||
|
||||
Vector<InputDispatchPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
|
||||
Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
|
||||
mPolicy->getVirtualKeyDefinitions(device->name, virtualKeyDefinitions);
|
||||
if (virtualKeyDefinitions.size() == 0) {
|
||||
return;
|
||||
@ -1720,7 +1716,7 @@ void InputReader::configureVirtualKeys(InputDevice* device) {
|
||||
int32_t touchScreenHeight = device->touchScreen.parameters.yAxis.range;
|
||||
|
||||
for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
|
||||
const InputDispatchPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
|
||||
const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
|
||||
virtualKeyDefinitions[i];
|
||||
|
||||
device->touchScreen.virtualKeys.add();
|
||||
@ -1779,6 +1775,15 @@ void InputReader::configureAbsoluteAxisInfo(InputDevice* device,
|
||||
LOGI(" %s: unknown axis values, setting to zero", name);
|
||||
}
|
||||
|
||||
void InputReader::configureExcludedDevices() {
|
||||
Vector<String8> excludedDeviceNames;
|
||||
mPolicy->getExcludedDeviceNames(excludedDeviceNames);
|
||||
|
||||
for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
|
||||
mEventHub->addExcludedDevice(excludedDeviceNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void InputReader::resetGlobalMetaState() {
|
||||
mGlobalMetaState = -1;
|
||||
}
|
||||
@ -1796,7 +1801,7 @@ int32_t InputReader::globalMetaState() {
|
||||
return mGlobalMetaState;
|
||||
}
|
||||
|
||||
void InputReader::updateGlobalVirtualKeyState() {
|
||||
void InputReader::updateExportedVirtualKeyState() {
|
||||
int32_t keyCode = -1, scanCode = -1;
|
||||
|
||||
for (size_t i = 0; i < mDevices.size(); i++) {
|
||||
@ -1809,20 +1814,96 @@ void InputReader::updateGlobalVirtualKeyState() {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
{ // acquire exported state lock
|
||||
AutoMutex _l(mExportedStateLock);
|
||||
|
||||
mGlobalVirtualKeyCode = keyCode;
|
||||
mGlobalVirtualScanCode = scanCode;
|
||||
}
|
||||
mExportedVirtualKeyCode = keyCode;
|
||||
mExportedVirtualScanCode = scanCode;
|
||||
} // release exported state lock
|
||||
}
|
||||
|
||||
bool InputReader::getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const {
|
||||
AutoMutex _l(mExportedStateLock);
|
||||
{ // acquire exported state lock
|
||||
AutoMutex _l(mExportedStateLock);
|
||||
|
||||
*outKeyCode = mGlobalVirtualKeyCode;
|
||||
*outScanCode = mGlobalVirtualScanCode;
|
||||
return mGlobalVirtualKeyCode != -1;
|
||||
*outKeyCode = mExportedVirtualKeyCode;
|
||||
*outScanCode = mExportedVirtualScanCode;
|
||||
return mExportedVirtualKeyCode != -1;
|
||||
} // release exported state lock
|
||||
}
|
||||
|
||||
void InputReader::updateExportedInputConfiguration() {
|
||||
int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH;
|
||||
int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS;
|
||||
int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV;
|
||||
|
||||
for (size_t i = 0; i < mDevices.size(); i++) {
|
||||
InputDevice* device = mDevices.valueAt(i);
|
||||
int32_t deviceClasses = device->classes;
|
||||
|
||||
if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
|
||||
touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
|
||||
}
|
||||
if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) {
|
||||
keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
|
||||
}
|
||||
if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) {
|
||||
navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
|
||||
} else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) {
|
||||
navigationConfig = InputConfiguration::NAVIGATION_DPAD;
|
||||
}
|
||||
}
|
||||
|
||||
{ // acquire exported state lock
|
||||
AutoMutex _l(mExportedStateLock);
|
||||
|
||||
mExportedInputConfiguration.touchScreen = touchScreenConfig;
|
||||
mExportedInputConfiguration.keyboard = keyboardConfig;
|
||||
mExportedInputConfiguration.navigation = navigationConfig;
|
||||
} // release exported state lock
|
||||
}
|
||||
|
||||
void InputReader::getCurrentInputConfiguration(InputConfiguration* outConfiguration) const {
|
||||
{ // acquire exported state lock
|
||||
AutoMutex _l(mExportedStateLock);
|
||||
|
||||
*outConfiguration = mExportedInputConfiguration;
|
||||
} // release exported state lock
|
||||
}
|
||||
|
||||
int32_t InputReader::getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t scanCode) const {
|
||||
{ // acquire exported state lock
|
||||
AutoMutex _l(mExportedStateLock);
|
||||
|
||||
if (mExportedVirtualScanCode == scanCode) {
|
||||
return KEY_STATE_VIRTUAL;
|
||||
}
|
||||
} // release exported state lock
|
||||
|
||||
return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode);
|
||||
}
|
||||
|
||||
int32_t InputReader::getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t keyCode) const {
|
||||
{ // acquire exported state lock
|
||||
AutoMutex _l(mExportedStateLock);
|
||||
|
||||
if (mExportedVirtualKeyCode == keyCode) {
|
||||
return KEY_STATE_VIRTUAL;
|
||||
}
|
||||
} // release exported state lock
|
||||
|
||||
return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode);
|
||||
}
|
||||
|
||||
int32_t InputReader::getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t sw) const {
|
||||
return mEventHub->getSwitchState(deviceId, deviceClasses, sw);
|
||||
}
|
||||
|
||||
bool InputReader::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
|
||||
return mEventHub->hasKeys(numCodes, keyCodes, outFlags);
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user