am 31e0ffe8: Merge "Native input event dispatching." into gingerbread
Merge commit '31e0ffe8444b70500cac319da084c4c45e62aca2' into gingerbread-plus-aosp * commit '31e0ffe8444b70500cac319da084c4c45e62aca2': Native input event dispatching.
This commit is contained in:
@@ -773,8 +773,6 @@ public abstract class WallpaperService extends Service {
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
if (mInputChannel != null) {
|
||||
InputQueue.unregisterInputChannel(mInputChannel);
|
||||
mInputChannel.dispose();
|
||||
mInputChannel = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,6 +781,15 @@ public abstract class WallpaperService extends Service {
|
||||
}
|
||||
mSurfaceHolder.mSurface.release();
|
||||
mCreated = false;
|
||||
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
// Dispose the input channel after removing the window so the Window Manager
|
||||
// doesn't interpret the input channel being closed as an abnormal termination.
|
||||
if (mInputChannel != null) {
|
||||
mInputChannel.dispose();
|
||||
mInputChannel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +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.
|
||||
*/
|
||||
|
||||
package android.view;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* These parameters are used by the native input dispatching code.
|
||||
* @hide
|
||||
*/
|
||||
public final class InputTarget {
|
||||
public InputChannel mInputChannel;
|
||||
public int mFlags;
|
||||
public long mTimeoutNanos;
|
||||
public float mXOffset;
|
||||
public float mYOffset;
|
||||
|
||||
/**
|
||||
* This flag indicates that subsequent event delivery should be held until the
|
||||
* current event is delivered to this target or a timeout occurs.
|
||||
*/
|
||||
public static int 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.
|
||||
*/
|
||||
public static int 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.
|
||||
*/
|
||||
public static int FLAG_CANCEL = 0x04;
|
||||
|
||||
public void recycle() {
|
||||
mInputChannel = null;
|
||||
}
|
||||
}
|
||||
@@ -1762,6 +1762,15 @@ public final class ViewRoot extends Handler implements ViewParent,
|
||||
sWindowSession.remove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
|
||||
if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
|
||||
// Dispose the input channel after removing the window so the Window Manager
|
||||
// doesn't interpret the input channel being closed as an abnormal termination.
|
||||
if (mInputChannel != null) {
|
||||
mInputChannel.dispose();
|
||||
mInputChannel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateConfiguration(Configuration config, boolean force) {
|
||||
|
||||
@@ -83,7 +83,7 @@ public interface WindowManagerPolicy {
|
||||
* Temporary flag added during the transition to the new native input dispatcher.
|
||||
* This will be removed when the old input dispatch code is deleted.
|
||||
*/
|
||||
public final static boolean ENABLE_NATIVE_INPUT_DISPATCH = false;
|
||||
public final static boolean ENABLE_NATIVE_INPUT_DISPATCH = true;
|
||||
|
||||
// flags for interceptKeyTq
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,6 @@ LOCAL_SRC_FILES:= \
|
||||
android_view_ViewRoot.cpp \
|
||||
android_view_InputChannel.cpp \
|
||||
android_view_InputQueue.cpp \
|
||||
android_view_InputTarget.cpp \
|
||||
android_view_KeyEvent.cpp \
|
||||
android_view_MotionEvent.cpp \
|
||||
android_text_AndroidCharacter.cpp \
|
||||
|
||||
@@ -164,7 +164,6 @@ extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env);
|
||||
extern int register_android_app_NativeActivity(JNIEnv *env);
|
||||
extern int register_android_view_InputChannel(JNIEnv* env);
|
||||
extern int register_android_view_InputQueue(JNIEnv* env);
|
||||
extern int register_android_view_InputTarget(JNIEnv* env);
|
||||
extern int register_android_view_KeyEvent(JNIEnv* env);
|
||||
extern int register_android_view_MotionEvent(JNIEnv* env);
|
||||
|
||||
@@ -1297,7 +1296,6 @@ static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_app_NativeActivity),
|
||||
REG_JNI(register_android_view_InputChannel),
|
||||
REG_JNI(register_android_view_InputQueue),
|
||||
REG_JNI(register_android_view_InputTarget),
|
||||
REG_JNI(register_android_view_KeyEvent),
|
||||
REG_JNI(register_android_view_MotionEvent),
|
||||
};
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
// Log debug messages about the dispatch cycle.
|
||||
#define DEBUG_DISPATCH_CYCLE 1
|
||||
#define DEBUG_DISPATCH_CYCLE 0
|
||||
|
||||
// Log debug messages about registrations.
|
||||
#define DEBUG_REGISTRATION 1
|
||||
#define DEBUG_REGISTRATION 0
|
||||
|
||||
|
||||
#include "JNIHelp.h"
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "InputTarget-JNI"
|
||||
|
||||
#include "JNIHelp.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <ui/InputDispatcher.h>
|
||||
#include <ui/InputTransport.h>
|
||||
#include "android_view_InputTarget.h"
|
||||
#include "android_view_InputChannel.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static struct {
|
||||
jclass clazz;
|
||||
|
||||
jfieldID mInputChannel;
|
||||
jfieldID mFlags;
|
||||
jfieldID mTimeoutNanos;
|
||||
jfieldID mXOffset;
|
||||
jfieldID mYOffset;
|
||||
} gInputTargetClassInfo;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void android_view_InputTarget_toNative(JNIEnv* env, jobject inputTargetObj,
|
||||
InputTarget* outInputTarget) {
|
||||
jobject inputChannelObj = env->GetObjectField(inputTargetObj,
|
||||
gInputTargetClassInfo.mInputChannel);
|
||||
jint flags = env->GetIntField(inputTargetObj,
|
||||
gInputTargetClassInfo.mFlags);
|
||||
jlong timeoutNanos = env->GetLongField(inputTargetObj,
|
||||
gInputTargetClassInfo.mTimeoutNanos);
|
||||
jfloat xOffset = env->GetFloatField(inputTargetObj,
|
||||
gInputTargetClassInfo.mXOffset);
|
||||
jfloat yOffset = env->GetFloatField(inputTargetObj,
|
||||
gInputTargetClassInfo.mYOffset);
|
||||
|
||||
outInputTarget->inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
|
||||
outInputTarget->flags = flags;
|
||||
outInputTarget->timeout = timeoutNanos;
|
||||
outInputTarget->xOffset = xOffset;
|
||||
outInputTarget->yOffset = yOffset;
|
||||
|
||||
env->DeleteLocalRef(inputChannelObj);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define FIND_CLASS(var, className) \
|
||||
var = env->FindClass(className); \
|
||||
LOG_FATAL_IF(! var, "Unable to find class " className); \
|
||||
var = jclass(env->NewGlobalRef(var));
|
||||
|
||||
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
|
||||
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
|
||||
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
|
||||
|
||||
int register_android_view_InputTarget(JNIEnv* env) {
|
||||
FIND_CLASS(gInputTargetClassInfo.clazz, "android/view/InputTarget");
|
||||
|
||||
GET_FIELD_ID(gInputTargetClassInfo.mInputChannel, gInputTargetClassInfo.clazz,
|
||||
"mInputChannel", "Landroid/view/InputChannel;");
|
||||
|
||||
GET_FIELD_ID(gInputTargetClassInfo.mFlags, gInputTargetClassInfo.clazz,
|
||||
"mFlags", "I");
|
||||
|
||||
GET_FIELD_ID(gInputTargetClassInfo.mTimeoutNanos, gInputTargetClassInfo.clazz,
|
||||
"mTimeoutNanos", "J");
|
||||
|
||||
GET_FIELD_ID(gInputTargetClassInfo.mXOffset, gInputTargetClassInfo.clazz,
|
||||
"mXOffset", "F");
|
||||
|
||||
GET_FIELD_ID(gInputTargetClassInfo.mYOffset, gInputTargetClassInfo.clazz,
|
||||
"mYOffset", "F");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
@@ -87,6 +87,9 @@ enum {
|
||||
// Indicates that the screen was dim when the event was received and the event
|
||||
// should brighten the device.
|
||||
POLICY_FLAG_BRIGHT_HERE = 0x20000000,
|
||||
|
||||
// Indicates that the dispatcher should call back into the policy before dispatching. */
|
||||
POLICY_FLAG_INTERCEPT_DISPATCH = 0x40000000,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -126,21 +126,21 @@ public:
|
||||
/* 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.
|
||||
/* Waits for key event input targets to become available.
|
||||
* If the event is being injected, injectorPid and injectorUid should specify the
|
||||
* process id and used id of the injecting application, otherwise they should both
|
||||
* be -1.
|
||||
* Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
|
||||
virtual int32_t getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
|
||||
virtual int32_t waitForKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
|
||||
int32_t injectorPid, int32_t injectorUid,
|
||||
Vector<InputTarget>& outTargets) = 0;
|
||||
|
||||
/* Gets the input targets for a motion event.
|
||||
/* Waits for motion event targets to become available.
|
||||
* If the event is being injected, injectorPid and injectorUid should specify the
|
||||
* process id and used id of the injecting application, otherwise they should both
|
||||
* be -1.
|
||||
* Returns one of the INPUT_EVENT_INJECTION_XXX constants. */
|
||||
virtual int32_t getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
|
||||
virtual int32_t waitForMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
|
||||
int32_t injectorPid, int32_t injectorUid,
|
||||
Vector<InputTarget>& outTargets) = 0;
|
||||
};
|
||||
@@ -186,6 +186,16 @@ public:
|
||||
virtual int32_t injectInputEvent(const InputEvent* event,
|
||||
int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
|
||||
|
||||
/* Preempts input dispatch in progress by making pending synchronous
|
||||
* dispatches asynchronous instead. This method is generally called during a focus
|
||||
* transition from one application to the next so as to enable the new application
|
||||
* to start receiving input as soon as possible without having to wait for the
|
||||
* old application to finish up.
|
||||
*
|
||||
* This method may be called on any thread (usually by the input manager).
|
||||
*/
|
||||
virtual void preemptInputDispatch() = 0;
|
||||
|
||||
/* Registers or unregister input channels that may be used as targets for input events.
|
||||
*
|
||||
* These methods may be called on any thread (usually by the input manager).
|
||||
@@ -233,6 +243,8 @@ public:
|
||||
virtual int32_t injectInputEvent(const InputEvent* event,
|
||||
int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);
|
||||
|
||||
virtual void preemptInputDispatch();
|
||||
|
||||
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
|
||||
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
|
||||
|
||||
|
||||
@@ -87,6 +87,14 @@ public:
|
||||
virtual int32_t injectInputEvent(const InputEvent* event,
|
||||
int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
|
||||
|
||||
/* Preempts input dispatch in progress by making pending synchronous
|
||||
* dispatches asynchronous instead. This method is generally called during a focus
|
||||
* transition from one application to the next so as to enable the new application
|
||||
* to start receiving input as soon as possible without having to wait for the
|
||||
* old application to finish up.
|
||||
*/
|
||||
virtual void preemptInputDispatch() = 0;
|
||||
|
||||
/* Gets input device configuration. */
|
||||
virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0;
|
||||
|
||||
@@ -130,6 +138,8 @@ public:
|
||||
virtual int32_t injectInputEvent(const InputEvent* event,
|
||||
int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);
|
||||
|
||||
virtual void preemptInputDispatch();
|
||||
|
||||
virtual void getInputConfiguration(InputConfiguration* outConfiguration) const;
|
||||
virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
|
||||
int32_t scanCode) const;
|
||||
|
||||
@@ -361,7 +361,11 @@ public:
|
||||
|
||||
// The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
|
||||
// passes through the dispatch pipeline.
|
||||
ACTION_BRIGHT_HERE = 0x00000008
|
||||
ACTION_BRIGHT_HERE = 0x00000008,
|
||||
|
||||
// The input dispatcher should add POLICY_FLAG_INTERCEPT_DISPATCH to the policy flags
|
||||
// it passed through the dispatch pipeline.
|
||||
ACTION_INTERCEPT_DISPATCH = 0x00000010
|
||||
};
|
||||
|
||||
/* Describes a virtual key. */
|
||||
|
||||
@@ -8,25 +8,25 @@
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
// Log detailed debug messages about each inbound event notification to the dispatcher.
|
||||
#define DEBUG_INBOUND_EVENT_DETAILS 1
|
||||
#define DEBUG_INBOUND_EVENT_DETAILS 0
|
||||
|
||||
// Log detailed debug messages about each outbound event processed by the dispatcher.
|
||||
#define DEBUG_OUTBOUND_EVENT_DETAILS 1
|
||||
#define DEBUG_OUTBOUND_EVENT_DETAILS 0
|
||||
|
||||
// Log debug messages about batching.
|
||||
#define DEBUG_BATCHING 1
|
||||
#define DEBUG_BATCHING 0
|
||||
|
||||
// Log debug messages about the dispatch cycle.
|
||||
#define DEBUG_DISPATCH_CYCLE 1
|
||||
#define DEBUG_DISPATCH_CYCLE 0
|
||||
|
||||
// Log debug messages about registrations.
|
||||
#define DEBUG_REGISTRATION 1
|
||||
#define DEBUG_REGISTRATION 0
|
||||
|
||||
// Log debug messages about performance statistics.
|
||||
#define DEBUG_PERFORMANCE_STATISTICS 1
|
||||
#define DEBUG_PERFORMANCE_STATISTICS 0
|
||||
|
||||
// Log debug messages about input event injection.
|
||||
#define DEBUG_INJECTION 1
|
||||
#define DEBUG_INJECTION 0
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <ui/InputDispatcher.h>
|
||||
@@ -249,9 +249,7 @@ void InputDispatcher::processKeyLockedInterruptible(
|
||||
entry->downTime);
|
||||
#endif
|
||||
|
||||
// TODO: Poke user activity.
|
||||
|
||||
if (entry->action == KEY_EVENT_ACTION_DOWN) {
|
||||
if (entry->action == KEY_EVENT_ACTION_DOWN && ! entry->isInjected()) {
|
||||
if (mKeyRepeatState.lastKeyEntry
|
||||
&& mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
|
||||
// We have seen two identical key downs in a row which indicates that the device
|
||||
@@ -277,14 +275,24 @@ void InputDispatcher::processKeyLockedInterruptible(
|
||||
|
||||
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
|
||||
// inbound event queue.
|
||||
KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
|
||||
|
||||
// Search the inbound queue for a key up corresponding to this device.
|
||||
// It doesn't make sense to generate a key repeat event if the key is already up.
|
||||
for (EventEntry* queuedEntry = mInboundQueue.head.next;
|
||||
queuedEntry != & mInboundQueue.tail; queuedEntry = entry->next) {
|
||||
if (queuedEntry->type == EventEntry::TYPE_KEY) {
|
||||
KeyEntry* queuedKeyEntry = static_cast<KeyEntry*>(queuedEntry);
|
||||
if (queuedKeyEntry->deviceId == entry->deviceId
|
||||
&& entry->action == KEY_EVENT_ACTION_UP) {
|
||||
resetKeyRepeatLocked();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Synthesize a key repeat after the repeat timeout expired.
|
||||
// We reuse the previous key entry if otherwise unreferenced.
|
||||
KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
|
||||
// Reuse the repeated key entry if it is otherwise unreferenced.
|
||||
uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
|
||||
if (entry->refCount == 1) {
|
||||
entry->eventTime = currentTime;
|
||||
@@ -366,7 +374,7 @@ void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible(
|
||||
entry->downTime, entry->eventTime);
|
||||
|
||||
mCurrentInputTargets.clear();
|
||||
int32_t injectionResult = mPolicy->getKeyEventTargets(& mReusableKeyEvent,
|
||||
int32_t injectionResult = mPolicy->waitForKeyEventTargets(& mReusableKeyEvent,
|
||||
entry->policyFlags, entry->injectorPid, entry->injectorUid,
|
||||
mCurrentInputTargets);
|
||||
|
||||
@@ -375,7 +383,9 @@ void InputDispatcher::identifyInputTargetsAndDispatchKeyLockedInterruptible(
|
||||
|
||||
setInjectionResultLocked(entry, injectionResult);
|
||||
|
||||
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
|
||||
if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED) {
|
||||
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
|
||||
}
|
||||
}
|
||||
|
||||
void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
|
||||
@@ -395,7 +405,7 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
|
||||
entry->firstSample.pointerCoords);
|
||||
|
||||
mCurrentInputTargets.clear();
|
||||
int32_t injectionResult = mPolicy->getMotionEventTargets(& mReusableMotionEvent,
|
||||
int32_t injectionResult = mPolicy->waitForMotionEventTargets(& mReusableMotionEvent,
|
||||
entry->policyFlags, entry->injectorPid, entry->injectorUid,
|
||||
mCurrentInputTargets);
|
||||
|
||||
@@ -404,7 +414,9 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
|
||||
|
||||
setInjectionResultLocked(entry, injectionResult);
|
||||
|
||||
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
|
||||
if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED) {
|
||||
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
|
||||
}
|
||||
}
|
||||
|
||||
void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
|
||||
@@ -514,7 +526,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
|
||||
connection->getInputChannelName());
|
||||
} else if (status == status_t(FAILED_TRANSACTION)) {
|
||||
LOGD("channel '%s' ~ Could not append motion sample to currently "
|
||||
"dispatchedmove event because the event has already been consumed. "
|
||||
"dispatched move event because the event has already been consumed. "
|
||||
"(Waiting for next dispatch cycle to start.)",
|
||||
connection->getInputChannelName());
|
||||
} else {
|
||||
@@ -1253,9 +1265,37 @@ void InputDispatcher::resetKeyRepeatLocked() {
|
||||
}
|
||||
}
|
||||
|
||||
void InputDispatcher::preemptInputDispatch() {
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("preemptInputDispatch");
|
||||
#endif
|
||||
|
||||
bool preemptedOne = false;
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
for (size_t i = 0; i < mActiveConnections.size(); i++) {
|
||||
Connection* connection = mActiveConnections[i];
|
||||
if (connection->hasPendingSyncTarget()) {
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("channel '%s' ~ Preempted pending synchronous dispatch",
|
||||
connection->getInputChannelName());
|
||||
#endif
|
||||
connection->outboundQueue.tail.prev->targetFlags &= ~ InputTarget::FLAG_SYNC;
|
||||
preemptedOne = true;
|
||||
}
|
||||
}
|
||||
} // release lock
|
||||
|
||||
if (preemptedOne) {
|
||||
// Wake up the poll loop so it can get a head start dispatching the next event.
|
||||
mPollLoop->wake();
|
||||
}
|
||||
}
|
||||
|
||||
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
|
||||
#if DEBUG_REGISTRATION
|
||||
LOGD("channel '%s' - Registered", inputChannel->getName().string());
|
||||
LOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().string());
|
||||
#endif
|
||||
|
||||
int receiveFd;
|
||||
@@ -1288,7 +1328,7 @@ 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());
|
||||
LOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
|
||||
#endif
|
||||
|
||||
int32_t receiveFd;
|
||||
|
||||
@@ -85,6 +85,10 @@ int32_t InputManager::injectInputEvent(const InputEvent* event,
|
||||
return mDispatcher->injectInputEvent(event, injectorPid, injectorUid, sync, timeoutMillis);
|
||||
}
|
||||
|
||||
void InputManager::preemptInputDispatch() {
|
||||
mDispatcher->preemptInputDispatch();
|
||||
}
|
||||
|
||||
void InputManager::getInputConfiguration(InputConfiguration* outConfiguration) const {
|
||||
mReader->getCurrentInputConfiguration(outConfiguration);
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
#define DEBUG_RAW_EVENTS 0
|
||||
|
||||
// Log debug messages about touch screen filtering hacks.
|
||||
#define DEBUG_HACKS 1
|
||||
#define DEBUG_HACKS 0
|
||||
|
||||
// Log debug messages about virtual key processing.
|
||||
#define DEBUG_VIRTUAL_KEYS 1
|
||||
#define DEBUG_VIRTUAL_KEYS 0
|
||||
|
||||
// Log debug messages about pointers.
|
||||
#define DEBUG_POINTERS 1
|
||||
#define DEBUG_POINTERS 0
|
||||
|
||||
// Log debug messages about pointer assignment calculations.
|
||||
#define DEBUG_POINTER_ASSIGNMENT 0
|
||||
@@ -630,7 +630,8 @@ void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
|
||||
int32_t pressure = currentTouch.pointers[currentIndex].pressure;
|
||||
|
||||
if (lastTouch.idBits.hasBit(id)) {
|
||||
// Pointer still down compute average.
|
||||
// Pointer was down before and is still down now.
|
||||
// Compute average over history trace.
|
||||
uint32_t start = averagingTouchFilter.historyStart[id];
|
||||
uint32_t end = averagingTouchFilter.historyEnd[id];
|
||||
|
||||
@@ -644,11 +645,15 @@ void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
|
||||
#endif
|
||||
|
||||
if (distance < AVERAGING_DISTANCE_LIMIT) {
|
||||
// Increment end index in preparation for recording new historical data.
|
||||
end += 1;
|
||||
if (end > AVERAGING_HISTORY_SIZE) {
|
||||
end = 0;
|
||||
}
|
||||
|
||||
// If the end index has looped back to the start index then we have filled
|
||||
// the historical trace up to the desired size so we drop the historical
|
||||
// data at the start of the trace.
|
||||
if (end == start) {
|
||||
start += 1;
|
||||
if (start > AVERAGING_HISTORY_SIZE) {
|
||||
@@ -656,23 +661,25 @@ void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
|
||||
}
|
||||
}
|
||||
|
||||
// Add the raw data to the historical trace.
|
||||
averagingTouchFilter.historyStart[id] = start;
|
||||
averagingTouchFilter.historyEnd[id] = end;
|
||||
averagingTouchFilter.historyData[end].pointers[id].x = x;
|
||||
averagingTouchFilter.historyData[end].pointers[id].y = y;
|
||||
averagingTouchFilter.historyData[end].pointers[id].pressure = pressure;
|
||||
|
||||
// Average over all historical positions in the trace by total pressure.
|
||||
int32_t averagedX = 0;
|
||||
int32_t averagedY = 0;
|
||||
int32_t totalPressure = 0;
|
||||
for (;;) {
|
||||
int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x;
|
||||
int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].x;
|
||||
int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y;
|
||||
int32_t historicalPressure = averagingTouchFilter.historyData[start]
|
||||
.pointers[id].pressure;
|
||||
|
||||
averagedX += historicalX;
|
||||
averagedY += historicalY;
|
||||
averagedX += historicalX * historicalPressure;
|
||||
averagedY += historicalY * historicalPressure;
|
||||
totalPressure += historicalPressure;
|
||||
|
||||
if (start == end) {
|
||||
@@ -1144,12 +1151,6 @@ void InputReader::onMultiTouchScreenStateChanged(nsecs_t when,
|
||||
|
||||
void InputReader::onSingleTouchScreenStateChanged(nsecs_t when,
|
||||
InputDevice* device) {
|
||||
static const uint32_t POSITION_FIELDS =
|
||||
InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_X
|
||||
| InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_Y
|
||||
| InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_PRESSURE
|
||||
| InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_TOOL_WIDTH;
|
||||
|
||||
/* Refresh display properties so we can map touch screen coords into display coords */
|
||||
|
||||
if (! refreshDisplayProperties()) {
|
||||
@@ -1167,10 +1168,19 @@ void InputReader::onSingleTouchScreenStateChanged(nsecs_t when,
|
||||
in->current.down = in->accumulator.btnTouch;
|
||||
}
|
||||
|
||||
if ((fields & POSITION_FIELDS) == POSITION_FIELDS) {
|
||||
if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_X) {
|
||||
in->current.x = in->accumulator.absX;
|
||||
}
|
||||
|
||||
if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_Y) {
|
||||
in->current.y = in->accumulator.absY;
|
||||
}
|
||||
|
||||
if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_PRESSURE) {
|
||||
in->current.pressure = in->accumulator.absPressure;
|
||||
}
|
||||
|
||||
if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_TOOL_WIDTH) {
|
||||
in->current.size = in->accumulator.absToolWidth;
|
||||
}
|
||||
|
||||
@@ -1323,18 +1333,23 @@ bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
|
||||
void InputReader::dispatchVirtualKey(nsecs_t when,
|
||||
InputDevice* device, uint32_t policyFlags,
|
||||
int32_t keyEventAction, int32_t keyEventFlags) {
|
||||
updateExportedVirtualKeyState();
|
||||
|
||||
int32_t keyCode = device->touchScreen.currentVirtualKey.keyCode;
|
||||
int32_t scanCode = device->touchScreen.currentVirtualKey.scanCode;
|
||||
nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
|
||||
int32_t metaState = globalMetaState();
|
||||
|
||||
updateExportedVirtualKeyState();
|
||||
|
||||
mPolicy->virtualKeyFeedback(when, device->id, keyEventAction, keyEventFlags,
|
||||
keyCode, scanCode, metaState, downTime);
|
||||
|
||||
mDispatcher->notifyKey(when, device->id, INPUT_EVENT_NATURE_KEY, policyFlags,
|
||||
keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
|
||||
int32_t policyActions = mPolicy->interceptKey(when, device->id,
|
||||
keyEventAction == KEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
|
||||
|
||||
if (applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
|
||||
mDispatcher->notifyKey(when, device->id, INPUT_EVENT_NATURE_KEY, policyFlags,
|
||||
keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
|
||||
}
|
||||
}
|
||||
|
||||
void InputReader::dispatchTouches(nsecs_t when,
|
||||
@@ -1609,6 +1624,10 @@ bool InputReader::applyStandardInputDispatchPolicyActions(nsecs_t when,
|
||||
*policyFlags |= POLICY_FLAG_BRIGHT_HERE;
|
||||
}
|
||||
|
||||
if (policyActions & InputReaderPolicyInterface::ACTION_INTERCEPT_DISPATCH) {
|
||||
*policyFlags |= POLICY_FLAG_INTERCEPT_DISPATCH;
|
||||
}
|
||||
|
||||
return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
|
||||
}
|
||||
|
||||
|
||||
@@ -430,10 +430,12 @@ status_t InputPublisher::appendMotionSample(
|
||||
reinterpret_cast<char*>(mSharedMessage);
|
||||
|
||||
if (newBytesUsed > mAshmemSize) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
LOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
|
||||
"buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d",
|
||||
mChannel->getName().string(),
|
||||
mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
|
||||
#endif
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
@@ -444,8 +446,10 @@ status_t InputPublisher::appendMotionSample(
|
||||
if (errno == EAGAIN) {
|
||||
// Only possible source of contention is the consumer having consumed (or being in the
|
||||
// process of consuming) the message and left the semaphore count at 0.
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
LOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
|
||||
"already been consumed.", mChannel->getName().string());
|
||||
#endif
|
||||
return FAILED_TRANSACTION;
|
||||
} else {
|
||||
LOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
|
||||
|
||||
@@ -14,18 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _ANDROID_VIEW_INPUTTARGET_H
|
||||
#define _ANDROID_VIEW_INPUTTARGET_H
|
||||
package com.android.server;
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
class InputTarget;
|
||||
|
||||
extern void android_view_InputTarget_toNative(JNIEnv* env, jobject inputTargetObj,
|
||||
InputTarget* outInputTarget);
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _ANDROID_OS_INPUTTARGET_H
|
||||
/**
|
||||
* Describes input-related application properties for use by the input dispatcher.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class InputApplication {
|
||||
// Application name.
|
||||
public String name;
|
||||
|
||||
// Dispatching timeout.
|
||||
public long dispatchingTimeoutNanos;
|
||||
|
||||
// The application window token.
|
||||
public Object token;
|
||||
}
|
||||
@@ -17,23 +17,20 @@
|
||||
package com.android.server;
|
||||
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.server.KeyInputQueue.VirtualKey;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Environment;
|
||||
import android.os.LocalPowerManager;
|
||||
import android.os.PowerManager;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputTarget;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.RawInputEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManagerPolicy;
|
||||
|
||||
@@ -85,6 +82,10 @@ public class InputManager {
|
||||
int injectorPid, int injectorUid, boolean sync, int timeoutMillis);
|
||||
private static native int nativeInjectMotionEvent(MotionEvent event, int nature,
|
||||
int injectorPid, int injectorUid, boolean sync, int timeoutMillis);
|
||||
private static native void nativeSetInputWindows(InputWindow[] windows);
|
||||
private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
|
||||
private static native void nativeSetFocusedApplication(InputApplication application);
|
||||
private static native void nativePreemptInputDispatch();
|
||||
|
||||
// Device class as defined by EventHub.
|
||||
private static final int CLASS_KEYBOARD = 0x00000001;
|
||||
@@ -284,6 +285,22 @@ public class InputManager {
|
||||
sync, timeoutMillis);
|
||||
}
|
||||
|
||||
public void setInputWindows(InputWindow[] windows) {
|
||||
nativeSetInputWindows(windows);
|
||||
}
|
||||
|
||||
public void setFocusedApplication(InputApplication application) {
|
||||
nativeSetFocusedApplication(application);
|
||||
}
|
||||
|
||||
public void preemptInputDispatch() {
|
||||
nativePreemptInputDispatch();
|
||||
}
|
||||
|
||||
public void setInputDispatchMode(boolean enabled, boolean frozen) {
|
||||
nativeSetInputDispatchMode(enabled, frozen);
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw) {
|
||||
// TODO
|
||||
}
|
||||
@@ -344,32 +361,43 @@ public class InputManager {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void notifyInputChannelBroken(InputChannel inputChannel) {
|
||||
mWindowManagerService.notifyInputChannelBroken(inputChannel);
|
||||
mWindowManagerService.mInputMonitor.notifyInputChannelBroken(inputChannel);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public long notifyInputChannelANR(InputChannel inputChannel) {
|
||||
return mWindowManagerService.notifyInputChannelANR(inputChannel);
|
||||
return mWindowManagerService.mInputMonitor.notifyInputChannelANR(inputChannel);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void notifyInputChannelRecoveredFromANR(InputChannel inputChannel) {
|
||||
mWindowManagerService.notifyInputChannelRecoveredFromANR(inputChannel);
|
||||
mWindowManagerService.mInputMonitor.notifyInputChannelRecoveredFromANR(inputChannel);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public int hackInterceptKey(int deviceId, int type, int scanCode,
|
||||
public long notifyANR(Object token) {
|
||||
return mWindowManagerService.mInputMonitor.notifyANR(token);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public int interceptKeyBeforeQueueing(int deviceId, int type, int scanCode,
|
||||
int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
|
||||
RawInputEvent event = new RawInputEvent();
|
||||
event.deviceId = deviceId;
|
||||
event.type = type;
|
||||
event.scancode = scanCode;
|
||||
event.keycode = keyCode;
|
||||
event.flags = policyFlags;
|
||||
event.value = value;
|
||||
event.when = whenNanos / 1000000;
|
||||
|
||||
return mWindowManagerPolicy.interceptKeyTq(event, isScreenOn);
|
||||
return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(deviceId, type,
|
||||
scanCode, keyCode, policyFlags, value, whenNanos, isScreenOn);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public boolean interceptKeyBeforeDispatching(InputChannel focus, int keyCode,
|
||||
int metaState, boolean down, int repeatCount, int policyFlags) {
|
||||
return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
|
||||
keyCode, metaState, down, repeatCount, policyFlags);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
|
||||
return mContext.checkPermission(
|
||||
android.Manifest.permission.INJECT_EVENTS, injectorPid, injectorUid)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -379,15 +407,14 @@ public class InputManager {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void pokeUserActivityForKey(long whenNanos) {
|
||||
long when = whenNanos / 1000000;
|
||||
mPowerManagerService.userActivity(when, false,
|
||||
LocalPowerManager.BUTTON_EVENT, false);
|
||||
public void pokeUserActivity(long eventTimeNanos, int eventType) {
|
||||
long eventTime = eventTimeNanos / 1000000;
|
||||
mPowerManagerService.userActivity(eventTime, false, eventType, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void notifyAppSwitchComing() {
|
||||
mWindowManagerService.mKeyWaiter.appSwitchComing();
|
||||
mWindowManagerService.mInputMonitor.notifyAppSwitchComing();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -485,24 +512,5 @@ public class InputManager {
|
||||
|
||||
return names.toArray(new String[names.size()]);
|
||||
}
|
||||
|
||||
// TODO All code related to target identification should be moved down into native.
|
||||
@SuppressWarnings("unused")
|
||||
public int getKeyEventTargets(InputTargetList inputTargets,
|
||||
KeyEvent event, int nature, int policyFlags,
|
||||
int injectorPid, int injectorUid) {
|
||||
inputTargets.clear();
|
||||
return mWindowManagerService.getKeyEventTargetsTd(
|
||||
inputTargets, event, nature, policyFlags, injectorPid, injectorUid);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public int getMotionEventTargets(InputTargetList inputTargets,
|
||||
MotionEvent event, int nature, int policyFlags,
|
||||
int injectorPid, int injectorUid) {
|
||||
inputTargets.clear();
|
||||
return mWindowManagerService.getMotionEventTargetsTd(
|
||||
inputTargets, event, nature, policyFlags, injectorPid, injectorUid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,104 +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.
|
||||
*/
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputTarget;
|
||||
|
||||
/**
|
||||
* A specialized list of input targets backed by an array.
|
||||
*
|
||||
* This class is part of an InputManager optimization to avoid allocating and copying
|
||||
* input target arrays unnecessarily on return from JNI callbacks. Internally, it keeps
|
||||
* an array full of demand-allocated InputTarget objects that it recycles each time the
|
||||
* list is cleared. The used portion of the array is padded with a null.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class InputTargetList {
|
||||
private InputTarget[] mArray;
|
||||
private int mCount;
|
||||
|
||||
/**
|
||||
* Creates an empty input target list.
|
||||
*/
|
||||
public InputTargetList() {
|
||||
mArray = new InputTarget[8];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the input target list.
|
||||
*/
|
||||
public void clear() {
|
||||
if (mCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int count = mCount;
|
||||
mCount = 0;
|
||||
mArray[count] = mArray[0];
|
||||
while (count > 0) {
|
||||
count -= 1;
|
||||
mArray[count].recycle();
|
||||
}
|
||||
mArray[0] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new input target to the input target list.
|
||||
* @param inputChannel The input channel of the target window.
|
||||
* @param flags Input target flags.
|
||||
* @param timeoutNanos The input dispatch timeout (before ANR) in nanoseconds or -1 if none.
|
||||
* @param xOffset An offset to add to motion X coordinates during delivery.
|
||||
* @param yOffset An offset to add to motion Y coordinates during delivery.
|
||||
*/
|
||||
public void add(InputChannel inputChannel, int flags, long timeoutNanos,
|
||||
float xOffset, float yOffset) {
|
||||
if (inputChannel == null) {
|
||||
throw new IllegalArgumentException("inputChannel must not be null");
|
||||
}
|
||||
|
||||
if (mCount + 1 == mArray.length) {
|
||||
InputTarget[] oldArray = mArray;
|
||||
mArray = new InputTarget[oldArray.length * 2];
|
||||
System.arraycopy(oldArray, 0, mArray, 0, mCount);
|
||||
}
|
||||
|
||||
// Grab InputTarget from tail (after used section) if available.
|
||||
InputTarget inputTarget = mArray[mCount + 1];
|
||||
if (inputTarget == null) {
|
||||
inputTarget = new InputTarget();
|
||||
}
|
||||
inputTarget.mInputChannel = inputChannel;
|
||||
inputTarget.mFlags = flags;
|
||||
inputTarget.mTimeoutNanos = timeoutNanos;
|
||||
inputTarget.mXOffset = xOffset;
|
||||
inputTarget.mYOffset = yOffset;
|
||||
|
||||
mArray[mCount] = inputTarget;
|
||||
mCount += 1;
|
||||
mArray[mCount] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input targets as a null-terminated array.
|
||||
* @return The input target array.
|
||||
*/
|
||||
public InputTarget[] toNullTerminatedArray() {
|
||||
return mArray;
|
||||
}
|
||||
}
|
||||
66
services/java/com/android/server/InputWindow.java
Normal file
66
services/java/com/android/server/InputWindow.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import android.view.InputChannel;
|
||||
|
||||
/**
|
||||
* Describes input-related window properties for use by the input dispatcher.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class InputWindow {
|
||||
// The input channel associated with the window.
|
||||
public InputChannel inputChannel;
|
||||
|
||||
// Window layout params attributes. (WindowManager.LayoutParams)
|
||||
public int layoutParamsFlags;
|
||||
public int layoutParamsType;
|
||||
|
||||
// Dispatching timeout.
|
||||
public long dispatchingTimeoutNanos;
|
||||
|
||||
// Window frame position.
|
||||
public int frameLeft;
|
||||
public int frameTop;
|
||||
|
||||
// Window touchable area.
|
||||
public int touchableAreaLeft;
|
||||
public int touchableAreaTop;
|
||||
public int touchableAreaRight;
|
||||
public int touchableAreaBottom;
|
||||
|
||||
// Window is visible.
|
||||
public boolean visible;
|
||||
|
||||
// Window has focus.
|
||||
public boolean hasFocus;
|
||||
|
||||
// Window has wallpaper. (window is the current wallpaper target)
|
||||
public boolean hasWallpaper;
|
||||
|
||||
// Input event dispatching is paused.
|
||||
public boolean paused;
|
||||
|
||||
// Id of process and user that owns the window.
|
||||
public int ownerPid;
|
||||
public int ownerUid;
|
||||
|
||||
public void recycle() {
|
||||
inputChannel = null;
|
||||
}
|
||||
}
|
||||
89
services/java/com/android/server/InputWindowList.java
Normal file
89
services/java/com/android/server/InputWindowList.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.server;
|
||||
|
||||
|
||||
/**
|
||||
* A specialized list of window information objects backed by an array.
|
||||
*
|
||||
* This class is part of an InputManager optimization to avoid allocating objects and arrays
|
||||
* unnecessarily. Internally, it keeps an array full of demand-allocated objects that it
|
||||
* recycles each time the list is cleared. The used portion of the array is padded with a null.
|
||||
*
|
||||
* The contents of the list are intended to be Z-ordered from top to bottom.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class InputWindowList {
|
||||
private InputWindow[] mArray;
|
||||
private int mCount;
|
||||
|
||||
/**
|
||||
* Creates an empty list.
|
||||
*/
|
||||
public InputWindowList() {
|
||||
mArray = new InputWindow[8];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the list.
|
||||
*/
|
||||
public void clear() {
|
||||
if (mCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int count = mCount;
|
||||
mCount = 0;
|
||||
mArray[count] = mArray[0];
|
||||
while (count > 0) {
|
||||
count -= 1;
|
||||
mArray[count].recycle();
|
||||
}
|
||||
mArray[0] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an uninitialized input window object to the list and returns it.
|
||||
*/
|
||||
public InputWindow add() {
|
||||
if (mCount + 1 == mArray.length) {
|
||||
InputWindow[] oldArray = mArray;
|
||||
mArray = new InputWindow[oldArray.length * 2];
|
||||
System.arraycopy(oldArray, 0, mArray, 0, mCount);
|
||||
}
|
||||
|
||||
// Grab object from tail (after used section) if available.
|
||||
InputWindow item = mArray[mCount + 1];
|
||||
if (item == null) {
|
||||
item = new InputWindow();
|
||||
}
|
||||
|
||||
mArray[mCount] = item;
|
||||
mCount += 1;
|
||||
mArray[mCount] = null;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input window objects as a null-terminated array.
|
||||
* @return The input window array.
|
||||
*/
|
||||
public InputWindow[] toNullTerminatedArray() {
|
||||
return mArray;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user