Merge "Fix a bug where we cleaned an apps external data when upgrading it. :(" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 1b7254f..f1a383f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -174217,6 +174217,17 @@
>
<implements name="android.os.Parcelable">
</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDevice"
return="android.view.InputDevice"
abstract="false"
@@ -174250,6 +174261,16 @@
visibility="public"
>
</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="mDeviceId"
type="int"
transient="false"
@@ -174893,17 +174914,6 @@
<parameter name="newFlags" type="int">
</parameter>
</method>
-<method name="describeContents"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="dispatch"
return="boolean"
abstract="false"
@@ -178103,17 +178113,6 @@
<parameter name="metaState" type="int">
</parameter>
</method>
-<method name="describeContents"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="findPointerIndex"
return="int"
abstract="false"
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9b7b2f4..d6b9212 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -26,6 +26,7 @@
import android.view.IRotationWatcher;
import android.view.IWindowSession;
import android.view.KeyEvent;
+import android.view.InputEvent;
import android.view.MotionEvent;
/**
@@ -50,10 +51,13 @@
boolean inputMethodClientHasFocus(IInputMethodClient client);
// These can only be called when injecting events to your own window,
- // or by holding the INJECT_EVENTS permission.
+ // or by holding the INJECT_EVENTS permission. These methods may block
+ // until pending input events are finished being dispatched even when 'sync' is false.
+ // Avoid calling these methods on your UI thread or use the 'NoWait' version instead.
boolean injectKeyEvent(in KeyEvent ev, boolean sync);
boolean injectPointerEvent(in MotionEvent ev, boolean sync);
boolean injectTrackballEvent(in MotionEvent ev, boolean sync);
+ boolean injectInputEventNoWait(in InputEvent ev);
// These can only be called when holding the MANAGE_APP_TOKENS permission.
void pauseKeyDispatching(IBinder token);
diff --git a/core/java/android/view/InputEvent.aidl b/core/java/android/view/InputEvent.aidl
new file mode 100644
index 0000000..61acaaf
--- /dev/null
+++ b/core/java/android/view/InputEvent.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android.view.InputEvent.aidl
+**
+** Copyright 2007, 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;
+
+parcelable InputEvent;
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index 78b73fe..9afd16e 100755
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -16,6 +16,7 @@
package android.view;
+import android.os.Parcel;
import android.os.Parcelable;
/**
@@ -25,6 +26,11 @@
protected int mDeviceId;
protected int mSource;
+ /** @hide */
+ protected static final int PARCEL_TOKEN_MOTION_EVENT = 1;
+ /** @hide */
+ protected static final int PARCEL_TOKEN_KEY_EVENT = 2;
+
/*package*/ InputEvent() {
}
@@ -69,4 +75,38 @@
public final void setSource(int source) {
mSource = source;
}
+
+ public final int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ protected final void readBaseFromParcel(Parcel in) {
+ mDeviceId = in.readInt();
+ mSource = in.readInt();
+ }
+
+ /** @hide */
+ protected final void writeBaseToParcel(Parcel out) {
+ out.writeInt(mDeviceId);
+ out.writeInt(mSource);
+ }
+
+ public static final Parcelable.Creator<InputEvent> CREATOR
+ = new Parcelable.Creator<InputEvent>() {
+ public InputEvent createFromParcel(Parcel in) {
+ int token = in.readInt();
+ if (token == PARCEL_TOKEN_KEY_EVENT) {
+ return KeyEvent.createFromParcelBody(in);
+ } else if (token == PARCEL_TOKEN_MOTION_EVENT) {
+ return MotionEvent.createFromParcelBody(in);
+ } else {
+ throw new IllegalStateException("Unexpected input event type token in parcel.");
+ }
+ }
+
+ public InputEvent[] newArray(int size) {
+ return new InputEvent[size];
+ }
+ };
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index dd0d21a3..9223e17 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1211,44 +1211,48 @@
public static final Parcelable.Creator<KeyEvent> CREATOR
= new Parcelable.Creator<KeyEvent>() {
public KeyEvent createFromParcel(Parcel in) {
- return new KeyEvent(in);
+ in.readInt(); // skip token, we already know this is a KeyEvent
+ return KeyEvent.createFromParcelBody(in);
}
public KeyEvent[] newArray(int size) {
return new KeyEvent[size];
}
};
-
- public int describeContents() {
- return 0;
+
+ /** @hide */
+ public static KeyEvent createFromParcelBody(Parcel in) {
+ return new KeyEvent(in);
+ }
+
+ private KeyEvent(Parcel in) {
+ readBaseFromParcel(in);
+
+ mAction = in.readInt();
+ mKeyCode = in.readInt();
+ mRepeatCount = in.readInt();
+ mMetaState = in.readInt();
+ mScanCode = in.readInt();
+ mFlags = in.readInt();
+ mDownTime = in.readLong();
+ mEventTime = in.readLong();
}
public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(PARCEL_TOKEN_KEY_EVENT);
+
+ writeBaseToParcel(out);
+
out.writeInt(mAction);
out.writeInt(mKeyCode);
out.writeInt(mRepeatCount);
out.writeInt(mMetaState);
- out.writeInt(mDeviceId);
- out.writeInt(mSource);
out.writeInt(mScanCode);
out.writeInt(mFlags);
out.writeLong(mDownTime);
out.writeLong(mEventTime);
}
- private KeyEvent(Parcel in) {
- mAction = in.readInt();
- mKeyCode = in.readInt();
- mRepeatCount = in.readInt();
- mMetaState = in.readInt();
- mDeviceId = in.readInt();
- mSource = in.readInt();
- mScanCode = in.readInt();
- mFlags = in.readInt();
- mDownTime = in.readLong();
- mEventTime = in.readLong();
- }
-
private native boolean native_isSystemKey(int keyCode);
private native boolean native_hasDefaultAction(int keyCode);
}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0e78570d..98fe73f 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1453,43 +1453,8 @@
public static final Parcelable.Creator<MotionEvent> CREATOR
= new Parcelable.Creator<MotionEvent>() {
public MotionEvent createFromParcel(Parcel in) {
- final int NP = in.readInt();
- final int NS = in.readInt();
- final int NI = NP * NS * NUM_SAMPLE_DATA;
-
- MotionEvent ev = obtain(NP, NS);
- ev.mNumPointers = NP;
- ev.mNumSamples = NS;
-
- ev.mDownTimeNano = in.readLong();
- ev.mAction = in.readInt();
- ev.mXOffset = in.readFloat();
- ev.mYOffset = in.readFloat();
- ev.mXPrecision = in.readFloat();
- ev.mYPrecision = in.readFloat();
- ev.mDeviceId = in.readInt();
- ev.mSource = in.readInt();
- ev.mEdgeFlags = in.readInt();
- ev.mMetaState = in.readInt();
-
- final int[] pointerIdentifiers = ev.mPointerIdentifiers;
- for (int i = 0; i < NP; i++) {
- pointerIdentifiers[i] = in.readInt();
- }
-
- final long[] eventTimeNanoSamples = ev.mEventTimeNanoSamples;
- for (int i = 0; i < NS; i++) {
- eventTimeNanoSamples[i] = in.readLong();
- }
-
- final float[] dataSamples = ev.mDataSamples;
- for (int i = 0; i < NI; i++) {
- dataSamples[i] = in.readFloat();
- }
-
- ev.mLastEventTimeNanoSampleIndex = NS - 1;
- ev.mLastDataSampleIndex = (NS - 1) * NP * NUM_SAMPLE_DATA;
- return ev;
+ in.readInt(); // skip token, we already know this is a MotionEvent
+ return MotionEvent.createFromParcelBody(in);
}
public MotionEvent[] newArray(int size) {
@@ -1497,11 +1462,50 @@
}
};
- public int describeContents() {
- return 0;
- }
+ /** @hide */
+ public static MotionEvent createFromParcelBody(Parcel in) {
+ final int NP = in.readInt();
+ final int NS = in.readInt();
+ final int NI = NP * NS * NUM_SAMPLE_DATA;
+
+ MotionEvent ev = obtain(NP, NS);
+ ev.mNumPointers = NP;
+ ev.mNumSamples = NS;
+
+ ev.readBaseFromParcel(in);
+
+ ev.mDownTimeNano = in.readLong();
+ ev.mAction = in.readInt();
+ ev.mXOffset = in.readFloat();
+ ev.mYOffset = in.readFloat();
+ ev.mXPrecision = in.readFloat();
+ ev.mYPrecision = in.readFloat();
+ ev.mEdgeFlags = in.readInt();
+ ev.mMetaState = in.readInt();
+
+ final int[] pointerIdentifiers = ev.mPointerIdentifiers;
+ for (int i = 0; i < NP; i++) {
+ pointerIdentifiers[i] = in.readInt();
+ }
+
+ final long[] eventTimeNanoSamples = ev.mEventTimeNanoSamples;
+ for (int i = 0; i < NS; i++) {
+ eventTimeNanoSamples[i] = in.readLong();
+ }
+ final float[] dataSamples = ev.mDataSamples;
+ for (int i = 0; i < NI; i++) {
+ dataSamples[i] = in.readFloat();
+ }
+
+ ev.mLastEventTimeNanoSampleIndex = NS - 1;
+ ev.mLastDataSampleIndex = (NS - 1) * NP * NUM_SAMPLE_DATA;
+ return ev;
+ }
+
public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(PARCEL_TOKEN_MOTION_EVENT);
+
final int NP = mNumPointers;
final int NS = mNumSamples;
final int NI = NP * NS * NUM_SAMPLE_DATA;
@@ -1509,14 +1513,14 @@
out.writeInt(NP);
out.writeInt(NS);
+ writeBaseToParcel(out);
+
out.writeLong(mDownTimeNano);
out.writeInt(mAction);
out.writeFloat(mXOffset);
out.writeFloat(mYOffset);
out.writeFloat(mXPrecision);
out.writeFloat(mYPrecision);
- out.writeInt(mDeviceId);
- out.writeInt(mSource);
out.writeInt(mEdgeFlags);
out.writeInt(mMetaState);
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 674852a..d3495fe 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -55,6 +55,22 @@
INPUT_EVENT_INJECTION_TIMED_OUT = 3
};
+/*
+ * Constants used to determine the input event injection synchronization mode.
+ */
+enum {
+ /* Injection is asynchronous and is assumed always to be successful. */
+ INPUT_EVENT_INJECTION_SYNC_NONE = 0,
+
+ /* Waits for previous events to be dispatched so that the input dispatcher can determine
+ * whether input event injection willbe permitted based on the current input focus.
+ * Does not wait for the input event to finish processing. */
+ INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1,
+
+ /* Waits for the input event to be completely processed. */
+ INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2,
+};
+
/*
* An input target specifies how an input event is to be dispatched to a particular window
@@ -176,15 +192,14 @@
float xPrecision, float yPrecision, nsecs_t downTime) = 0;
/* Injects an input event and optionally waits for sync.
- * This method may block even if sync is false because it must wait for previous events
- * to be dispatched before it can determine whether input event injection will be
- * permitted based on the current input focus.
+ * The synchronization mode determines whether the method blocks while waiting for
+ * input injection to proceed.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants.
*
* This method may be called on any thread (usually by the input manager).
*/
virtual int32_t injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
+ int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) = 0;
/* Preempts input dispatch in progress by making pending synchronous
* dispatches asynchronous instead. This method is generally called during a focus
@@ -241,7 +256,7 @@
float xPrecision, float yPrecision, nsecs_t downTime);
virtual int32_t injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);
+ int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
virtual void preemptInputDispatch();
@@ -267,11 +282,13 @@
int32_t type;
nsecs_t eventTime;
- int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING
- int32_t injectorPid; // -1 if not injected
- int32_t injectorUid; // -1 if not injected
+ int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING
+ bool injectionIsAsync; // set to true if injection is not waiting for the result
+ int32_t injectorPid; // -1 if not injected
+ int32_t injectorUid; // -1 if not injected
bool dispatchInProgress; // initially false, set to true while dispatching
+ int32_t pendingSyncDispatches; // the number of synchronous dispatches in progress
inline bool isInjected() { return injectorPid >= 0; }
};
@@ -340,6 +357,10 @@
// headMotionSample will be initialized to tailMotionSample and tailMotionSample
// will be set to NULL.
MotionSample* tailMotionSample;
+
+ inline bool isSyncTarget() {
+ return targetFlags & InputTarget::FLAG_SYNC;
+ }
};
// A command entry captures state and behavior for an action to be performed in the
@@ -497,8 +518,7 @@
// Since there can only ever be at most one such target at a time, if there is one,
// it must be at the tail because nothing else can be enqueued after it.
inline bool hasPendingSyncTarget() {
- return ! outboundQueue.isEmpty()
- && (outboundQueue.tail.prev->targetFlags & InputTarget::FLAG_SYNC);
+ return ! outboundQueue.isEmpty() && outboundQueue.tail.prev->isSyncTarget();
}
// Gets the time since the current event was originally obtained from the input driver.
@@ -559,11 +579,12 @@
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
- Condition mFullySynchronizedCondition;
- bool isFullySynchronizedLocked();
EventEntry* createEntryFromInputEventLocked(const InputEvent* event);
void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
+ Condition mInjectionSyncFinishedCondition;
+ void decrementPendingSyncDispatchesLocked(EventEntry* entry);
+
// Key repeat tracking.
// XXX Move this up to the input reader instead.
struct KeyRepeatState {
diff --git a/include/ui/InputManager.h b/include/ui/InputManager.h
index 7ebec10..4012c69 100644
--- a/include/ui/InputManager.h
+++ b/include/ui/InputManager.h
@@ -79,13 +79,12 @@
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
/* Injects an input event and optionally waits for sync.
- * This method may block even if sync is false because it must wait for previous events
- * to be dispatched before it can determine whether input event injection will be
- * permitted based on the current input focus.
+ * The synchronization mode determines whether the method blocks while waiting for
+ * input injection to proceed.
* Returns one of the INPUT_EVENT_INJECTION_XXX constants.
*/
virtual int32_t injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) = 0;
+ int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) = 0;
/* Preempts input dispatch in progress by making pending synchronous
* dispatches asynchronous instead. This method is generally called during a focus
@@ -142,7 +141,7 @@
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
virtual int32_t injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis);
+ int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
virtual void preemptInputDispatch();
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index a55864b..b53f140 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -184,11 +184,6 @@
// Run any deferred commands.
skipPoll |= runCommandsLockedInterruptible();
-
- // Wake up synchronization waiters, if needed.
- if (isFullySynchronizedLocked()) {
- mFullySynchronizedCondition.broadcast();
- }
} // release lock
// If we dispatched anything, don't poll just now. Wait for the next iteration.
@@ -560,6 +555,10 @@
dispatchEntry->headMotionSample = NULL;
dispatchEntry->tailMotionSample = NULL;
+ if (dispatchEntry->isSyncTarget()) {
+ eventEntry->pendingSyncDispatches += 1;
+ }
+
// Handle the case where we could not stream a new motion sample because the consumer has
// already consumed the motion event (otherwise the corresponding dispatch entry would
// still be in the outbound queue for this connection). We set the head motion sample
@@ -789,6 +788,9 @@
}
// Finished.
connection->outboundQueue.dequeueAtHead();
+ if (dispatchEntry->isSyncTarget()) {
+ decrementPendingSyncDispatchesLocked(dispatchEntry->eventEntry);
+ }
mAllocator.releaseDispatchEntry(dispatchEntry);
} else {
// If the head is not in progress, then we must have already dequeued the in
@@ -854,6 +856,9 @@
if (! connection->outboundQueue.isEmpty()) {
do {
DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
+ if (dispatchEntry->isSyncTarget()) {
+ decrementPendingSyncDispatchesLocked(dispatchEntry->eventEntry);
+ }
mAllocator.releaseDispatchEntry(dispatchEntry);
} while (! connection->outboundQueue.isEmpty());
@@ -1097,7 +1102,7 @@
Connection* connection = mActiveConnections.itemAt(i);
if (! connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.tail.prev;
- if (dispatchEntry->targetFlags & InputTarget::FLAG_SYNC) {
+ if (dispatchEntry->isSyncTarget()) {
if (dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION) {
goto NoBatchingOrStreaming;
}
@@ -1148,11 +1153,11 @@
}
int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) {
+ int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) {
#if DEBUG_INBOUND_EVENT_DETAILS
LOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "sync=%d, timeoutMillis=%d",
- event->getType(), injectorPid, injectorUid, sync, timeoutMillis);
+ "syncMode=%d, timeoutMillis=%d",
+ event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis);
#endif
nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
@@ -1167,6 +1172,10 @@
injectedEntry->injectorPid = injectorPid;
injectedEntry->injectorUid = injectorUid;
+ if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
+ injectedEntry->injectionIsAsync = true;
+ }
+
wasEmpty = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(injectedEntry);
@@ -1180,37 +1189,59 @@
{ // acquire lock
AutoMutex _l(mLock);
- for (;;) {
- injectionResult = injectedEntry->injectionResult;
- if (injectionResult != INPUT_EVENT_INJECTION_PENDING) {
- break;
- }
+ if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
+ injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
+ } else {
+ for (;;) {
+ injectionResult = injectedEntry->injectionResult;
+ if (injectionResult != INPUT_EVENT_INJECTION_PENDING) {
+ break;
+ }
- nsecs_t remainingTimeout = endTime - now();
- if (remainingTimeout <= 0) {
- injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
- sync = false;
- break;
- }
-
- mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout);
- }
-
- if (sync) {
- while (! isFullySynchronizedLocked()) {
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
+#if DEBUG_INJECTION
+ LOGD("injectInputEvent - Timed out waiting for injection result "
+ "to become available.");
+#endif
injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
break;
}
- mFullySynchronizedCondition.waitRelative(mLock, remainingTimeout);
+ mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout);
+ }
+
+ if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED
+ && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) {
+ while (injectedEntry->pendingSyncDispatches != 0) {
+#if DEBUG_INJECTION
+ LOGD("injectInputEvent - Waiting for %d pending synchronous dispatches.",
+ injectedEntry->pendingSyncDispatches);
+#endif
+ nsecs_t remainingTimeout = endTime - now();
+ if (remainingTimeout <= 0) {
+#if DEBUG_INJECTION
+ LOGD("injectInputEvent - Timed out waiting for pending synchronous "
+ "dispatches to finish.");
+#endif
+ injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
+ break;
+ }
+
+ mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout);
+ }
}
}
mAllocator.releaseEventEntry(injectedEntry);
} // release lock
+#if DEBUG_INJECTION
+ LOGD("injectInputEvent - Finished with result %d. "
+ "injectorPid=%d, injectorUid=%d",
+ injectionResult, injectorPid, injectorUid);
+#endif
+
return injectionResult;
}
@@ -1222,13 +1253,35 @@
injectionResult, entry->injectorPid, entry->injectorUid);
#endif
+ if (entry->injectionIsAsync) {
+ // Log the outcome since the injector did not wait for the injection result.
+ switch (injectionResult) {
+ case INPUT_EVENT_INJECTION_SUCCEEDED:
+ LOGV("Asynchronous input event injection succeeded.");
+ break;
+ case INPUT_EVENT_INJECTION_FAILED:
+ LOGW("Asynchronous input event injection failed.");
+ break;
+ case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
+ LOGW("Asynchronous input event injection permission denied.");
+ break;
+ case INPUT_EVENT_INJECTION_TIMED_OUT:
+ LOGW("Asynchronous input event injection timed out.");
+ break;
+ }
+ }
+
entry->injectionResult = injectionResult;
mInjectionResultAvailableCondition.broadcast();
}
}
-bool InputDispatcher::isFullySynchronizedLocked() {
- return mInboundQueue.isEmpty() && mActiveConnections.isEmpty();
+void InputDispatcher::decrementPendingSyncDispatchesLocked(EventEntry* entry) {
+ entry->pendingSyncDispatches -= 1;
+
+ if (entry->isInjected() && entry->pendingSyncDispatches == 0) {
+ mInjectionSyncFinishedCondition.broadcast();
+ }
}
InputDispatcher::EventEntry* InputDispatcher::createEntryFromInputEventLocked(
@@ -1498,8 +1551,10 @@
entry->dispatchInProgress = false;
entry->eventTime = eventTime;
entry->injectionResult = INPUT_EVENT_INJECTION_PENDING;
+ entry->injectionIsAsync = false;
entry->injectorPid = -1;
entry->injectorUid = -1;
+ entry->pendingSyncDispatches = 0;
}
InputDispatcher::ConfigurationChangedEntry*
diff --git a/libs/ui/InputManager.cpp b/libs/ui/InputManager.cpp
index bf23479..ed4f07b 100644
--- a/libs/ui/InputManager.cpp
+++ b/libs/ui/InputManager.cpp
@@ -81,8 +81,8 @@
}
int32_t InputManager::injectInputEvent(const InputEvent* event,
- int32_t injectorPid, int32_t injectorUid, bool sync, int32_t timeoutMillis) {
- return mDispatcher->injectInputEvent(event, injectorPid, injectorUid, sync, timeoutMillis);
+ int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) {
+ return mDispatcher->injectInputEvent(event, injectorPid, injectorUid, syncMode, timeoutMillis);
}
void InputManager::preemptInputDispatch() {
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index c5183e4..56e2977 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -1600,7 +1600,7 @@
case InputReaderPolicyInterface::ROTATION_90: {
float xTemp = x;
x = y;
- y = mOrientedSurfaceWidth - xTemp;
+ y = mSurfaceWidth - xTemp;
orientation -= M_PI_2;
if (orientation < - M_PI_2) {
orientation += M_PI;
@@ -1608,14 +1608,14 @@
break;
}
case InputReaderPolicyInterface::ROTATION_180: {
- x = mOrientedSurfaceWidth - x;
- y = mOrientedSurfaceHeight - y;
+ x = mSurfaceWidth - x;
+ y = mSurfaceHeight - y;
orientation = - orientation;
break;
}
case InputReaderPolicyInterface::ROTATION_270: {
float xTemp = x;
- x = mOrientedSurfaceHeight - y;
+ x = mSurfaceHeight - y;
y = xTemp;
orientation += M_PI_2;
if (orientation > M_PI_2) {
diff --git a/libs/utils/StreamingZipInflater.cpp b/libs/utils/StreamingZipInflater.cpp
index c13760a..7ebde78 100644
--- a/libs/utils/StreamingZipInflater.cpp
+++ b/libs/utils/StreamingZipInflater.cpp
@@ -20,10 +20,10 @@
#include <utils/FileMap.h>
#include <utils/StreamingZipInflater.h>
#include <string.h>
-#include <unistd.h>
+#include <stddef.h>
#include <assert.h>
-static inline size_t min(size_t a, size_t b) { return (a < b) ? a : b; }
+static inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; }
using namespace android;
@@ -116,10 +116,10 @@
ssize_t StreamingZipInflater::read(void* outBuf, size_t count) {
uint8_t* dest = (uint8_t*) outBuf;
size_t bytesRead = 0;
- size_t toRead = min(count, size_t(mOutTotalSize - mOutCurPosition));
+ size_t toRead = min_of(count, size_t(mOutTotalSize - mOutCurPosition));
while (toRead > 0) {
// First, write from whatever we already have decoded and ready to go
- size_t deliverable = min(toRead, mOutLastDecoded - mOutDeliverable);
+ size_t deliverable = min_of(toRead, mOutLastDecoded - mOutDeliverable);
if (deliverable > 0) {
if (outBuf != NULL) memcpy(dest, mOutBuf + mOutDeliverable, deliverable);
mOutDeliverable += deliverable;
@@ -188,7 +188,7 @@
assert(mDataMap == NULL);
if (mInNextChunkOffset < mInTotalSize) {
- size_t toRead = min(mInBufSize, mInTotalSize - mInNextChunkOffset);
+ size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
if (toRead > 0) {
ssize_t didRead = ::read(mFd, mInBuf, toRead);
//LOGD("Reading input chunk, size %08x didread %08x", toRead, didRead);
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index b7bde6b..c27cfc8 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 3572d10..252b42a 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -307,6 +307,7 @@
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output);
+ PlaybackThread *effectThread = NULL;
if (thread == NULL) {
LOGE("unknown output thread");
lStatus = BAD_VALUE;
@@ -324,12 +325,19 @@
LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) {
- // prevent same audio session on different output threads
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.keyAt(i) != output &&
- mPlaybackThreads.valueAt(i)->hasAudioSession(*sessionId)) {
- lStatus = BAD_VALUE;
- goto Exit;
+ sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
+ if (mPlaybackThreads.keyAt(i) != output) {
+ // prevent same audio session on different output threads
+ uint32_t sessions = t->hasAudioSession(*sessionId);
+ if (sessions & PlaybackThread::TRACK_SESSION) {
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ // check if an effect with same session ID is waiting for a track to be created
+ if (sessions & PlaybackThread::EFFECT_SESSION) {
+ effectThread = t.get();
+ }
}
}
lSessionId = *sessionId;
@@ -344,6 +352,14 @@
track = thread->createTrack_l(client, streamType, sampleRate, format,
channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);
+
+ // move effect chain to this output thread if an effect on same session was waiting
+ // for a track to be created
+ if (lStatus == NO_ERROR && effectThread != NULL) {
+ Mutex::Autolock _dl(thread->mLock);
+ Mutex::Autolock _sl(effectThread->mLock);
+ moveEffectChain_l(lSessionId, effectThread, thread, true);
+ }
}
if (lStatus == NO_ERROR) {
trackHandle = new TrackHandle(track);
@@ -1377,7 +1393,7 @@
// create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
Vector< sp<EffectChain> > effectChains = mEffectChains;
for (size_t i = 0; i < effectChains.size(); i ++) {
- mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this);
+ mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this, false);
}
}
@@ -1394,22 +1410,24 @@
return mOutput->getRenderPosition(dspFrames);
}
-bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
+uint32_t AudioFlinger::PlaybackThread::hasAudioSession(int sessionId)
{
Mutex::Autolock _l(mLock);
+ uint32_t result = 0;
if (getEffectChain_l(sessionId) != 0) {
- return true;
+ result = EFFECT_SESSION;
}
for (size_t i = 0; i < mTracks.size(); ++i) {
sp<Track> track = mTracks[i];
if (sessionId == track->sessionId() &&
!(track->mCblk->flags & CBLK_INVALID_MSK)) {
- return true;
+ result |= TRACK_SESSION;
+ break;
}
}
- return false;
+ return result;
}
uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId)
@@ -1997,7 +2015,7 @@
uint32_t AudioFlinger::MixerThread::idleSleepTimeUs()
{
- return (uint32_t)((mFrameCount * 1000) / mSampleRate) * 1000;
+ return (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2;
}
// ----------------------------------------------------------------------------
@@ -2458,7 +2476,7 @@
{
uint32_t time;
if (AudioSystem::isLinearPCM(mFormat)) {
- time = (uint32_t)((mFrameCount * 1000) / mSampleRate) * 1000;
+ time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2;
} else {
time = 10000;
}
@@ -4704,11 +4722,17 @@
} else {
// look for the thread where the specified audio session is present
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId)) {
+ if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
output = mPlaybackThreads.keyAt(i);
break;
}
}
+ // If no output thread contains the requested session ID, default to
+ // first output. The effect chain will be moved to the correct output
+ // thread when a track with the same session ID is created
+ if (output == 0 && mPlaybackThreads.size()) {
+ output = mPlaybackThreads.keyAt(0);
+ }
}
}
PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -4764,7 +4788,7 @@
Mutex::Autolock _dl(dstThread->mLock);
Mutex::Autolock _sl(srcThread->mLock);
- moveEffectChain_l(session, srcThread, dstThread);
+ moveEffectChain_l(session, srcThread, dstThread, false);
return NO_ERROR;
}
@@ -4772,7 +4796,8 @@
// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
status_t AudioFlinger::moveEffectChain_l(int session,
AudioFlinger::PlaybackThread *srcThread,
- AudioFlinger::PlaybackThread *dstThread)
+ AudioFlinger::PlaybackThread *dstThread,
+ bool reRegister)
{
LOGV("moveEffectChain_l() session %d from thread %p to thread %p",
session, srcThread, dstThread);
@@ -4784,7 +4809,7 @@
return INVALID_OPERATION;
}
- // remove chain first. This is usefull only if reconfiguring effect chain on same output thread,
+ // remove chain first. This is useful only if reconfiguring effect chain on same output thread,
// so that a new chain is created with correct parameters when first effect is added. This is
// otherwise unecessary as removeEffect_l() will remove the chain when last effect is
// removed.
@@ -4792,10 +4817,32 @@
// transfer all effects one by one so that new effect chain is created on new thread with
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
+ int dstOutput = dstThread->id();
+ sp<EffectChain> dstChain;
+ uint32_t strategy;
sp<EffectModule> effect = chain->getEffectFromId_l(0);
while (effect != 0) {
srcThread->removeEffect_l(effect);
dstThread->addEffect_l(effect);
+ // if the move request is not received from audio policy manager, the effect must be
+ // re-registered with the new strategy and output
+ if (dstChain == 0) {
+ dstChain = effect->chain().promote();
+ if (dstChain == 0) {
+ LOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
+ srcThread->addEffect_l(effect);
+ return NO_INIT;
+ }
+ strategy = dstChain->strategy();
+ }
+ if (reRegister) {
+ AudioSystem::unregisterEffect(effect->id());
+ AudioSystem::registerEffect(&effect->desc(),
+ dstOutput,
+ strategy,
+ session,
+ effect->id());
+ }
effect = chain->getEffectFromId_l(0);
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8f667a3..5520551 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -613,7 +613,15 @@
void disconnectEffect(const sp< EffectModule>& effect,
const wp<EffectHandle>& handle);
- bool hasAudioSession(int sessionId);
+ // return values for hasAudioSession (bit field)
+ enum effect_state {
+ EFFECT_SESSION = 0x1, // the audio session corresponds to at least one
+ // effect
+ TRACK_SESSION = 0x2 // the audio session corresponds to at least one
+ // track
+ };
+
+ uint32_t hasAudioSession(int sessionId);
sp<EffectChain> getEffectChain(int sessionId);
sp<EffectChain> getEffectChain_l(int sessionId);
status_t addEffectChain_l(const sp<EffectChain>& chain);
@@ -776,7 +784,8 @@
int nextUniqueId();
status_t moveEffectChain_l(int session,
AudioFlinger::PlaybackThread *srcThread,
- AudioFlinger::PlaybackThread *dstThread);
+ AudioFlinger::PlaybackThread *dstThread,
+ bool reRegister);
friend class AudioBuffer;
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 9a1d017..9195123 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -29,6 +29,7 @@
import android.util.Slog;
import android.util.Xml;
import android.view.InputChannel;
+import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
@@ -76,10 +77,8 @@
int[] keyCodes, boolean[] keyExists);
private static native void nativeRegisterInputChannel(InputChannel inputChannel);
private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
- private static native int nativeInjectKeyEvent(KeyEvent event,
- int injectorPid, int injectorUid, boolean sync, int timeoutMillis);
- private static native int nativeInjectMotionEvent(MotionEvent event,
- int injectorPid, int injectorUid, boolean sync, int timeoutMillis);
+ private static native int nativeInjectInputEvent(InputEvent event,
+ int injectorPid, int injectorUid, int syncMode, 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);
@@ -92,6 +91,11 @@
static final int INPUT_EVENT_INJECTION_FAILED = 2;
static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
+ // Input event injection synchronization modes defined in InputDispatcher.h
+ static final int INPUT_EVENT_INJECTION_SYNC_NONE = 0;
+ static final int INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1;
+ static final int INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH = 2;
+
// Key states (may be returned by queries about the current state of a
// particular key code, scan code or switch).
@@ -107,7 +111,6 @@
/** The key is down but is a virtual key press that is being emulated by the system. */
public static final int KEY_STATE_VIRTUAL = 2;
-
public InputManager(Context context, WindowManagerService windowManagerService) {
this.mContext = context;
this.mWindowManagerService = windowManagerService;
@@ -239,19 +242,30 @@
}
/**
- * Injects a key event into the event system on behalf of an application.
- * This method may block even if sync is false because it must wait for previous events
- * to be dispatched before it can determine whether input event injection will be
- * permitted based on the current input focus.
+ * Injects an input event into the event system on behalf of an application.
+ * The synchronization mode determines whether the method blocks while waiting for
+ * input injection to proceed.
+ *
+ * {@link #INPUT_EVENT_INJECTION_SYNC_NONE} never blocks. Injection is asynchronous and
+ * is assumed always to be successful.
+ *
+ * {@link #INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT} waits for previous events to be
+ * dispatched so that the input dispatcher can determine whether input event injection will
+ * be permitted based on the current input focus. Does not wait for the input event to
+ * finish processing.
+ *
+ * {@link #INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH} waits for the input event to
+ * be completely processed.
+ *
* @param event The event to inject.
* @param injectorPid The pid of the injecting application.
* @param injectorUid The uid of the injecting application.
- * @param sync If true, waits for the event to be completed before returning.
+ * @param syncMode The synchronization mode.
* @param timeoutMillis The injection timeout in milliseconds.
* @return One of the INPUT_EVENT_INJECTION_XXX constants.
*/
- public int injectKeyEvent(KeyEvent event, int injectorPid, int injectorUid,
- boolean sync, int timeoutMillis) {
+ public int injectInputEvent(InputEvent event, int injectorPid, int injectorUid,
+ int syncMode, int timeoutMillis) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
@@ -261,38 +275,8 @@
if (timeoutMillis <= 0) {
throw new IllegalArgumentException("timeoutMillis must be positive");
}
-
- return nativeInjectKeyEvent(event, injectorPid, injectorUid,
- sync, timeoutMillis);
- }
-
- /**
- * Injects a motion event into the event system on behalf of an application.
- * This method may block even if sync is false because it must wait for previous events
- * to be dispatched before it can determine whether input event injection will be
- * permitted based on the current input focus.
- * @param event The event to inject.
- * @param sync If true, waits for the event to be completed before returning.
- * @param injectorPid The pid of the injecting application.
- * @param injectorUid The uid of the injecting application.
- * @param sync If true, waits for the event to be completed before returning.
- * @param timeoutMillis The injection timeout in milliseconds.
- * @return One of the INPUT_EVENT_INJECTION_XXX constants.
- */
- public int injectMotionEvent(MotionEvent event, int injectorPid, int injectorUid,
- boolean sync, int timeoutMillis) {
- if (event == null) {
- throw new IllegalArgumentException("event must not be null");
- }
- if (injectorPid < 0 || injectorUid < 0) {
- throw new IllegalArgumentException("injectorPid and injectorUid must not be negative.");
- }
- if (timeoutMillis <= 0) {
- throw new IllegalArgumentException("timeoutMillis must be positive");
- }
-
- return nativeInjectMotionEvent(event, injectorPid, injectorUid,
- sync, timeoutMillis);
+
+ return nativeInjectInputEvent(event, injectorPid, injectorUid, syncMode, timeoutMillis);
}
public void setInputWindows(InputWindow[] windows) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index eb0f343..5615232 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -103,6 +103,7 @@
import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.InputDevice;
+import android.view.InputEvent;
import android.view.InputQueue;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -5382,6 +5383,8 @@
/**
* Injects a keystroke event into the UI.
+ * Even when sync is false, this method may block while waiting for current
+ * input events to be dispatched.
*
* @param ev A motion event describing the keystroke action. (Be sure to use
* {@link SystemClock#uptimeMillis()} as the timebase.)
@@ -5414,8 +5417,10 @@
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
- final int result = mInputManager.injectKeyEvent(newEvent,
- pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
+ final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
+ sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
+ : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+ INJECTION_TIMEOUT_MILLIS);
Binder.restoreCallingIdentity(ident);
return reportInjectionResult(result);
@@ -5423,6 +5428,8 @@
/**
* Inject a pointer (touch) event into the UI.
+ * Even when sync is false, this method may block while waiting for current
+ * input events to be dispatched.
*
* @param ev A motion event describing the pointer (touch) action. (As noted in
* {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
@@ -5440,8 +5447,10 @@
newEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
}
- final int result = mInputManager.injectMotionEvent(newEvent,
- pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
+ final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
+ sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
+ : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+ INJECTION_TIMEOUT_MILLIS);
Binder.restoreCallingIdentity(ident);
return reportInjectionResult(result);
@@ -5449,6 +5458,8 @@
/**
* Inject a trackball (navigation device) event into the UI.
+ * Even when sync is false, this method may block while waiting for current
+ * input events to be dispatched.
*
* @param ev A motion event describing the trackball action. (As noted in
* {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
@@ -5466,8 +5477,31 @@
newEvent.setSource(InputDevice.SOURCE_TRACKBALL);
}
- final int result = mInputManager.injectMotionEvent(newEvent,
- pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
+ final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
+ sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
+ : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+ INJECTION_TIMEOUT_MILLIS);
+
+ Binder.restoreCallingIdentity(ident);
+ return reportInjectionResult(result);
+ }
+
+ /**
+ * Inject an input event into the UI without waiting for dispatch to commence.
+ * This variant is useful for fire-and-forget input event injection. It does not
+ * block any longer than it takes to enqueue the input event.
+ *
+ * @param ev An input event. (Be sure to set the input source correctly.)
+ * @return Returns true if event was dispatched, false if it was dropped for any reason
+ */
+ public boolean injectInputEventNoWait(InputEvent ev) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+
+ final int result = mInputManager.injectInputEvent(ev, pid, uid,
+ InputManager.INPUT_EVENT_INJECTION_SYNC_NONE,
+ INJECTION_TIMEOUT_MILLIS);
Binder.restoreCallingIdentity(ident);
return reportInjectionResult(result);
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 4b4c784..f8c9a61 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -892,7 +892,7 @@
Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) {
if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
- } else if (hasCapability(GPS_CAPABILITY_MSA)) {
+ } else if (hasCapability(GPS_CAPABILITY_MSB)) {
mPositionMode = GPS_POSITION_MODE_MS_BASED;
}
}
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index a332376..0982b32 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -180,6 +180,14 @@
jfieldID token;
} gInputApplicationClassInfo;
+static struct {
+ jclass clazz;
+} gKeyEventClassInfo;
+
+static struct {
+ jclass clazz;
+} gMotionEventClassInfo;
+
// ----------------------------------------------------------------------------
static inline nsecs_t now() {
@@ -2051,32 +2059,29 @@
}
}
-static jint android_server_InputManager_nativeInjectKeyEvent(JNIEnv* env, jclass clazz,
- jobject keyEventObj, jint injectorPid, jint injectorUid,
- jboolean sync, jint timeoutMillis) {
+static jint android_server_InputManager_nativeInjectInputEvent(JNIEnv* env, jclass clazz,
+ jobject inputEventObj, jint injectorPid, jint injectorUid,
+ jint syncMode, jint timeoutMillis) {
if (checkInputManagerUnitialized(env)) {
return INPUT_EVENT_INJECTION_FAILED;
}
- KeyEvent keyEvent;
- android_view_KeyEvent_toNative(env, keyEventObj, & keyEvent);
+ if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
+ KeyEvent keyEvent;
+ android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
- return gNativeInputManager->getInputManager()->injectInputEvent(& keyEvent,
- injectorPid, injectorUid, sync, timeoutMillis);
-}
+ return gNativeInputManager->getInputManager()->injectInputEvent(& keyEvent,
+ injectorPid, injectorUid, syncMode, timeoutMillis);
+ } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
+ MotionEvent motionEvent;
+ android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent);
-static jint android_server_InputManager_nativeInjectMotionEvent(JNIEnv* env, jclass clazz,
- jobject motionEventObj, jint injectorPid, jint injectorUid,
- jboolean sync, jint timeoutMillis) {
- if (checkInputManagerUnitialized(env)) {
+ return gNativeInputManager->getInputManager()->injectInputEvent(& motionEvent,
+ injectorPid, injectorUid, syncMode, timeoutMillis);
+ } else {
+ jniThrowRuntimeException(env, "Invalid input event type.");
return INPUT_EVENT_INJECTION_FAILED;
}
-
- MotionEvent motionEvent;
- android_view_MotionEvent_toNative(env, motionEventObj, & motionEvent);
-
- return gNativeInputManager->getInputManager()->injectInputEvent(& motionEvent,
- injectorPid, injectorUid, sync, timeoutMillis);
}
static void android_server_InputManager_nativeSetInputWindows(JNIEnv* env, jclass clazz,
@@ -2148,10 +2153,8 @@
(void*) android_server_InputManager_nativeRegisterInputChannel },
{ "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V",
(void*) android_server_InputManager_nativeUnregisterInputChannel },
- { "nativeInjectKeyEvent", "(Landroid/view/KeyEvent;IIZI)I",
- (void*) android_server_InputManager_nativeInjectKeyEvent },
- { "nativeInjectMotionEvent", "(Landroid/view/MotionEvent;IIZI)I",
- (void*) android_server_InputManager_nativeInjectMotionEvent },
+ { "nativeInjectInputEvent", "(Landroid/view/InputEvent;IIII)I",
+ (void*) android_server_InputManager_nativeInjectInputEvent },
{ "nativeSetInputWindows", "([Lcom/android/server/InputWindow;)V",
(void*) android_server_InputManager_nativeSetInputWindows },
{ "nativeSetFocusedApplication", "(Lcom/android/server/InputApplication;)V",
@@ -2318,6 +2321,14 @@
GET_FIELD_ID(gInputApplicationClassInfo.token, gInputApplicationClassInfo.clazz,
"token", "Ljava/lang/Object;");
+ // KeyEvent
+
+ FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
+
+ // MotionEVent
+
+ FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
+
return 0;
}