From 85a3176704b5bfbeece9bd928369fbb76eec7dc6 Mon Sep 17 00:00:00 2001
From: Jeff Brown
Date: Wed, 1 Sep 2010 17:01:00 -0700
Subject: [PATCH] Add support for secure views.
Added the MotionEvent.FLAG_WINDOW_IS_OBSCURED flag which is set by the
input manager whenever another visible window is partly or wholly obscured
the target of a touch event so that applications can filter touches
accordingly.
Added a "filterTouchesWhenObscured" attribute to View which can be used to
enable filtering of touches when the view's window is obscured.
Change-Id: I936d9c85013fd2d77fb296a600528d30a29027d2
---
api/current.xml | 105 ++++++++++++--
core/java/android/view/MotionEvent.java | 40 +++++-
core/java/android/view/View.java | 88 +++++++++++-
core/java/android/view/ViewGroup.java | 4 +
.../android/view/WindowManagerPolicy.java | 2 +
core/jni/android_view_MotionEvent.cpp | 8 +-
core/res/res/values/attrs.xml | 6 +
core/res/res/values/public.xml | 1 +
include/ui/Input.h | 9 ++
include/ui/InputDispatcher.h | 28 ++--
include/ui/InputTransport.h | 2 +
libs/ui/Input.cpp | 2 +
libs/ui/InputDispatcher.cpp | 38 +++--
libs/ui/InputReader.cpp | 4 +-
libs/ui/InputTransport.cpp | 13 +-
.../tests/InputPublisherAndConsumer_test.cpp | 18 +--
native/android/input.cpp | 4 +
native/include/android/input.h | 19 +++
.../java/com/android/server/InputWindow.java | 10 +-
.../android/server/WindowManagerService.java | 8 ++
.../jni/com_android_server_InputManager.cpp | 131 ++++++++++++++++--
21 files changed, 467 insertions(+), 73 deletions(-)
diff --git a/api/current.xml b/api/current.xml
index e95c26ff9ecb5..1eb46c7d72954 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -5861,17 +5861,6 @@
visibility="public"
>
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
> ACTION_POINTER_INDEX_SHIFT;
}
+ /**
+ * Gets the motion event flags.
+ *
+ * @see #FLAG_WINDOW_IS_OBSCURED
+ */
+ public final int getFlags() {
+ return mFlags;
+ }
+
/**
* Returns the time (in ms) when the user originally pressed down to start
* a stream of position events.
@@ -1285,7 +1311,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
/**
- * Sets the bitfield indicating which edges, if any, where touched by this
+ * Sets the bitfield indicating which edges, if any, were touched by this
* MotionEvent.
*
* @see #getEdgeFlags()
@@ -1480,6 +1506,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
ev.mYPrecision = in.readFloat();
ev.mEdgeFlags = in.readInt();
ev.mMetaState = in.readInt();
+ ev.mFlags = in.readInt();
final int[] pointerIdentifiers = ev.mPointerIdentifiers;
for (int i = 0; i < NP; i++) {
@@ -1521,6 +1548,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
out.writeFloat(mYPrecision);
out.writeInt(mEdgeFlags);
out.writeInt(mMetaState);
+ out.writeInt(mFlags);
final int[] pointerIdentifiers = mPointerIdentifiers;
for (int i = 0; i < NP; i++) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7332c16d15f9e..fe003a4ece6f1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -542,6 +542,28 @@ import java.util.WeakHashMap;
* take care of redrawing the appropriate views until the animation completes.
*
*
+ *
+ * Security
+ *
+ * Sometimes it is essential that an application be able to verify that an action
+ * is being performed with the full knowledge and consent of the user, such as
+ * granting a permission request, making a purchase or clicking on an advertisement.
+ * Unfortunately, a malicious application could try to spoof the user into
+ * performing these actions, unaware, by concealing the intended purpose of the view.
+ * As a remedy, the framework offers a touch filtering mechanism that can be used to
+ * improve the security of views that provide access to sensitive functionality.
+ *
+ * To enable touch filtering, call {@link #setFilterTouchesWhenObscured} or set the
+ * andoird:filterTouchesWhenObscured attribute to true. When enabled, the framework
+ * will discard touches that are received whenever the view's window is obscured by
+ * another visible window. As a result, the view will not receive touches whenever a
+ * toast, dialog or other window appears above the view's window.
+ *
+ * For more fine-grained control over security, consider overriding the
+ * {@link #onFilterTouchEventForSecurity} method to implement your own security policy.
+ * See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}.
+ *
+ *
* @attr ref android.R.styleable#View_background
* @attr ref android.R.styleable#View_clickable
* @attr ref android.R.styleable#View_contentDescription
@@ -550,6 +572,7 @@ import java.util.WeakHashMap;
* @attr ref android.R.styleable#View_id
* @attr ref android.R.styleable#View_fadingEdge
* @attr ref android.R.styleable#View_fadingEdgeLength
+ * @attr ref android.R.styleable#View_filterTouchesWhenObscured
* @attr ref android.R.styleable#View_fitsSystemWindows
* @attr ref android.R.styleable#View_isScrollContainer
* @attr ref android.R.styleable#View_focusable
@@ -711,7 +734,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*/
static final int SCROLLBARS_MASK = 0x00000300;
- // note 0x00000400 and 0x00000800 are now available for next flags...
+ /**
+ * Indicates that the view should filter touches when its window is obscured.
+ * Refer to the class comments for more information about this security feature.
+ * {@hide}
+ */
+ static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400;
+
+ // note flag value 0x00000800 is now available for next flags...
/**
* This view doesn't show fading edges.
@@ -2052,6 +2082,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
viewFlagMasks |= KEEP_SCREEN_ON;
}
break;
+ case R.styleable.View_filterTouchesWhenObscured:
+ if (a.getBoolean(attr, false)) {
+ viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED;
+ viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED;
+ }
+ break;
case R.styleable.View_nextFocusLeft:
mNextFocusLeftId = a.getResourceId(attr, View.NO_ID);
break;
@@ -3389,6 +3425,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK);
}
+ /**
+ * Gets whether the framework should discard touches when the view's
+ * window is obscured by another visible window.
+ * Refer to the {@link View} security documentation for more details.
+ *
+ * @return True if touch filtering is enabled.
+ *
+ * @see #setFilterTouchesWhenObscured(boolean)
+ * @attr ref android.R.styleable#View_filterTouchesWhenObscured
+ */
+ @ViewDebug.ExportedProperty
+ public boolean getFilterTouchesWhenObscured() {
+ return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0;
+ }
+
+ /**
+ * Sets whether the framework should discard touches when the view's
+ * window is obscured by another visible window.
+ * Refer to the {@link View} security documentation for more details.
+ *
+ * @param enabled True if touch filtering should be enabled.
+ *
+ * @see #getFilterTouchesWhenObscured
+ * @attr ref android.R.styleable#View_filterTouchesWhenObscured
+ */
+ public void setFilterTouchesWhenObscured(boolean enabled) {
+ setFlags(enabled ? 0 : FILTER_TOUCHES_WHEN_OBSCURED,
+ FILTER_TOUCHES_WHEN_OBSCURED);
+ }
/**
* Returns whether this View is able to take focus.
@@ -3808,6 +3873,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchTouchEvent(MotionEvent event) {
+ if (!onFilterTouchEventForSecurity(event)) {
+ return false;
+ }
+
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
@@ -3815,6 +3884,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
return onTouchEvent(event);
}
+ /**
+ * Filter the touch event to apply security policies.
+ *
+ * @param event The motion event to be filtered.
+ * @return True if the event should be dispatched, false if the event should be dropped.
+ *
+ * @see #getFilterTouchesWhenObscured
+ */
+ public boolean onFilterTouchEventForSecurity(MotionEvent event) {
+ if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0
+ && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
+ // Window is obscured, drop this touch.
+ return false;
+ }
+ return true;
+ }
+
/**
* Pass a trackball motion event down to the focused view.
*
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 715992912368b..28bed3a0d4896 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -822,6 +822,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (!onFilterTouchEventForSecurity(ev)) {
+ return false;
+ }
+
final int action = ev.getAction();
final float xf = ev.getX();
final float yf = ev.getY();
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 659f9cd673c6e..76701a937886b 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -74,6 +74,8 @@ public interface WindowManagerPolicy {
public final static int FLAG_MENU = 0x00000040;
public final static int FLAG_LAUNCHER = 0x00000080;
+ public final static int FLAG_INJECTED = 0x01000000;
+
public final static int FLAG_WOKE_HERE = 0x10000000;
public final static int FLAG_BRIGHT_HERE = 0x20000000;
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index fe247e87f096a..93fd54fedddae 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -46,6 +46,7 @@ static struct {
jfieldID mYPrecision;
jfieldID mEdgeFlags;
jfieldID mMetaState;
+ jfieldID mFlags;
jfieldID mNumPointers;
jfieldID mNumSamples;
jfieldID mPointerIdentifiers;
@@ -91,6 +92,8 @@ jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* even
event->getEdgeFlags());
env->SetIntField(eventObj, gMotionEventClassInfo.mMetaState,
event->getMetaState());
+ env->SetIntField(eventObj, gMotionEventClassInfo.mFlags,
+ event->getFlags());
env->SetIntField(eventObj, gMotionEventClassInfo.mNumPointers,
numPointers);
env->SetIntField(eventObj, gMotionEventClassInfo.mNumSamples,
@@ -162,6 +165,7 @@ void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
jfloat yPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mYPrecision);
jint edgeFlags = env->GetIntField(eventObj, gMotionEventClassInfo.mEdgeFlags);
jint metaState = env->GetIntField(eventObj, gMotionEventClassInfo.mMetaState);
+ jint flags = env->GetIntField(eventObj, gMotionEventClassInfo.mFlags);
jint numPointers = env->GetIntField(eventObj, gMotionEventClassInfo.mNumPointers);
jint numSamples = env->GetIntField(eventObj, gMotionEventClassInfo.mNumSamples);
jintArray pointerIdentifierArray = jintArray(env->GetObjectField(eventObj,
@@ -196,7 +200,7 @@ void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
samplePointerCoords[j].orientation = *(srcDataSamples++);
}
- event->initialize(deviceId, source, action, edgeFlags, metaState,
+ event->initialize(deviceId, source, action, flags, edgeFlags, metaState,
xOffset, yOffset, xPrecision, yPrecision, downTimeNano, sampleEventTime,
numPointers, pointerIdentifiers, samplePointerCoords);
@@ -281,6 +285,8 @@ int register_android_view_MotionEvent(JNIEnv* env) {
"mEdgeFlags", "I");
GET_FIELD_ID(gMotionEventClassInfo.mMetaState, gMotionEventClassInfo.clazz,
"mMetaState", "I");
+ GET_FIELD_ID(gMotionEventClassInfo.mFlags, gMotionEventClassInfo.clazz,
+ "mFlags", "I");
GET_FIELD_ID(gMotionEventClassInfo.mNumPointers, gMotionEventClassInfo.clazz,
"mNumPointers", "I");
GET_FIELD_ID(gMotionEventClassInfo.mNumSamples, gMotionEventClassInfo.clazz,
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 1130b69094480..13c3e7eacab95 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1274,6 +1274,12 @@
be saved. -->
+
+
+
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 86e79c809d02c..28a7cca1adc1b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1254,6 +1254,7 @@
+
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 3fa825f9bf427..b587e94db5708 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -78,6 +78,11 @@ enum {
POLICY_FLAG_RAW_MASK = 0x0000ffff,
+ /* These flags are set by the input dispatcher. */
+
+ // Indicates that the input event was injected.
+ POLICY_FLAG_INJECTED = 0x01000000,
+
/* These flags are set by the input reader policy as it intercepts each event. */
// Indicates that the screen was off when the event was received and the event
@@ -225,6 +230,8 @@ public:
inline int32_t getAction() const { return mAction; }
+ inline int32_t getFlags() const { return mFlags; }
+
inline int32_t getEdgeFlags() const { return mEdgeFlags; }
inline int32_t getMetaState() const { return mMetaState; }
@@ -343,6 +350,7 @@ public:
int32_t deviceId,
int32_t source,
int32_t action,
+ int32_t flags,
int32_t edgeFlags,
int32_t metaState,
float xOffset,
@@ -370,6 +378,7 @@ public:
private:
int32_t mAction;
+ int32_t mFlags;
int32_t mEdgeFlags;
int32_t mMetaState;
float mXOffset;
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index aed4fa112b145..711a658c35981 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -84,14 +84,22 @@ struct InputTarget {
* current event is delivered to this target or a timeout occurs. */
FLAG_SYNC = 0x01,
- /* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of
- * this target and so should instead be delivered as an ACTION_OUTSIDE to this target. */
+ /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
+ * of the area of this target and so should instead be delivered as an
+ * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
FLAG_OUTSIDE = 0x02,
/* This flag indicates that a KeyEvent or MotionEvent is being canceled.
- * In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set.
- * In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL. */
- FLAG_CANCEL = 0x04
+ * In the case of a key event, it should be delivered with flag
+ * AKEY_EVENT_FLAG_CANCELED set.
+ * In the case of a motion event, it should be delivered with action
+ * AMOTION_EVENT_ACTION_CANCEL instead. */
+ FLAG_CANCEL = 0x04,
+
+ /* This flag indicates that the target of a MotionEvent is partly or wholly
+ * obscured by another visible window above it. The motion event should be
+ * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
+ FLAG_WINDOW_IS_OBSCURED = 0x08,
};
// The input channel to be targeted.
@@ -193,7 +201,8 @@ public:
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
- uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags,
+ uint32_t policyFlags, int32_t action, int32_t flags,
+ int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) = 0;
@@ -257,7 +266,8 @@ public:
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime);
virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
- uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags,
+ uint32_t policyFlags, int32_t action, int32_t flags,
+ int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
@@ -327,6 +337,7 @@ private:
int32_t source;
uint32_t policyFlags;
int32_t action;
+ int32_t flags;
int32_t metaState;
int32_t edgeFlags;
float xPrecision;
@@ -458,7 +469,8 @@ private:
int32_t repeatCount, nsecs_t downTime);
MotionEntry* obtainMotionEntry(nsecs_t eventTime,
int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
- int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision,
+ int32_t flags, int32_t metaState, int32_t edgeFlags,
+ float xPrecision, float yPrecision,
nsecs_t downTime, uint32_t pointerCount,
const int32_t* pointerIds, const PointerCoords* pointerCoords);
DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry);
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 31ec7019a624d..82831e29b6fc6 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -135,6 +135,7 @@ struct InputMessage {
struct {
int32_t action;
+ int32_t flags;
int32_t metaState;
int32_t edgeFlags;
nsecs_t downTime;
@@ -218,6 +219,7 @@ public:
int32_t deviceId,
int32_t source,
int32_t action,
+ int32_t flags,
int32_t edgeFlags,
int32_t metaState,
float xOffset,
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 4973cd89f226d..811edaf8a26fc 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -129,6 +129,7 @@ void MotionEvent::initialize(
int32_t deviceId,
int32_t source,
int32_t action,
+ int32_t flags,
int32_t edgeFlags,
int32_t metaState,
float xOffset,
@@ -142,6 +143,7 @@ void MotionEvent::initialize(
const PointerCoords* pointerCoords) {
InputEvent::initialize(deviceId, source);
mAction = action;
+ mFlags = flags;
mEdgeFlags = edgeFlags;
mMetaState = metaState;
mXOffset = xOffset;
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 886c7856debb2..e5b7f280befc5 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -392,9 +392,11 @@ void InputDispatcher::processKeyRepeatLockedInterruptible(
void InputDispatcher::processMotionLockedInterruptible(
nsecs_t currentTime, MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
- LOGD("processMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, "
+ LOGD("processMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
+ "action=0x%x, flags=0x%x, "
"metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
- entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action,
+ entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
+ entry->action, entry->flags,
entry->metaState, entry->edgeFlags, entry->xPrecision, entry->yPrecision,
entry->downTime);
@@ -406,7 +408,7 @@ void InputDispatcher::processMotionLockedInterruptible(
}
for (uint32_t i = 0; i < entry->pointerCount; i++) {
LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, "
- "touchMajor=%f, touchMinor=%d, toolMajor=%f, toolMinor=%f, "
+ "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
"orientation=%f",
i, entry->pointerIds[i],
sample->pointerCoords[i].x, sample->pointerCoords[i].y,
@@ -465,7 +467,7 @@ void InputDispatcher::identifyInputTargetsAndDispatchMotionLockedInterruptible(
mCurrentInputTargetsValid = false;
mLock.unlock();
- mReusableMotionEvent.initialize(entry->deviceId, entry->source, entry->action,
+ mReusableMotionEvent.initialize(entry->deviceId, entry->source, entry->action, entry->flags,
entry->edgeFlags, entry->metaState,
0, 0, entry->xPrecision, entry->yPrecision,
entry->downTime, entry->eventTime, entry->pointerCount, entry->pointerIds,
@@ -698,12 +700,16 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
// Apply target flags.
int32_t action = motionEntry->action;
+ int32_t flags = motionEntry->flags;
if (dispatchEntry->targetFlags & InputTarget::FLAG_OUTSIDE) {
action = AMOTION_EVENT_ACTION_OUTSIDE;
}
if (dispatchEntry->targetFlags & InputTarget::FLAG_CANCEL) {
action = AMOTION_EVENT_ACTION_CANCEL;
}
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
+ flags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+ }
// If headMotionSample is non-NULL, then it points to the first new sample that we
// were unable to dispatch during the previous cycle so we resume dispatching from
@@ -726,7 +732,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
// Publish the motion event and the first motion sample.
status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
- motionEntry->source, action, motionEntry->edgeFlags, motionEntry->metaState,
+ motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
xOffset, yOffset,
motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, firstMotionSample->eventTime,
@@ -1073,18 +1079,18 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou
}
void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
- uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags,
+ uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
LOGD("notifyMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
- "action=0x%x, metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, "
- "downTime=%lld",
- eventTime, deviceId, source, policyFlags, action, metaState, edgeFlags,
+ "action=0x%x, flags=0x%x, metaState=0x%x, edgeFlags=0x%x, "
+ "xPrecision=%f, yPrecision=%f, downTime=%lld",
+ eventTime, deviceId, source, policyFlags, action, flags, metaState, edgeFlags,
xPrecision, yPrecision, downTime);
for (uint32_t i = 0; i < pointerCount; i++) {
LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, "
- "touchMajor=%f, touchMinor=%d, toolMajor=%f, toolMinor=%f, "
+ "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
"orientation=%f",
i, pointerIds[i], pointerCoords[i].x, pointerCoords[i].y,
pointerCoords[i].pressure, pointerCoords[i].size,
@@ -1209,7 +1215,7 @@ NoBatchingOrStreaming:;
// Just enqueue a new motion event.
MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime,
- deviceId, source, policyFlags, action, metaState, edgeFlags,
+ deviceId, source, policyFlags, action, flags, metaState, edgeFlags,
xPrecision, yPrecision, downTime,
pointerCount, pointerIds, pointerCoords);
@@ -1359,7 +1365,7 @@ InputDispatcher::EventEntry* InputDispatcher::createEntryFromInputEventLocked(
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
const KeyEvent* keyEvent = static_cast(event);
- uint32_t policyFlags = 0; // XXX consider adding a policy flag to track injected events
+ uint32_t policyFlags = POLICY_FLAG_INJECTED;
KeyEntry* keyEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags,
@@ -1371,7 +1377,7 @@ InputDispatcher::EventEntry* InputDispatcher::createEntryFromInputEventLocked(
case AINPUT_EVENT_TYPE_MOTION: {
const MotionEvent* motionEvent = static_cast(event);
- uint32_t policyFlags = 0; // XXX consider adding a policy flag to track injected events
+ uint32_t policyFlags = POLICY_FLAG_INJECTED;
const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
@@ -1379,7 +1385,8 @@ InputDispatcher::EventEntry* InputDispatcher::createEntryFromInputEventLocked(
MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
- motionEvent->getAction(), motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
+ motionEvent->getAction(), motionEvent->getFlags(),
+ motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
motionEvent->getDownTime(), uint32_t(pointerCount),
motionEvent->getPointerIds(), samplePointerCoords);
@@ -1664,7 +1671,7 @@ InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t ev
}
InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsecs_t eventTime,
- int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
+ int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action, int32_t flags,
int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision,
nsecs_t downTime, uint32_t pointerCount,
const int32_t* pointerIds, const PointerCoords* pointerCoords) {
@@ -1676,6 +1683,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec
entry->source = source;
entry->policyFlags = policyFlags;
entry->action = action;
+ entry->flags = flags;
entry->metaState = metaState;
entry->edgeFlags = edgeFlags;
entry->xPrecision = xPrecision;
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 8ffb48debe8fb..d57b38c2e2f72 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -1153,7 +1153,7 @@ void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEv
int32_t pointerId = 0;
getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags,
- motionEventAction, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime);
}
@@ -2324,7 +2324,7 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
} // release lock
getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
- motionEventAction, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
+ motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
pointerCount, pointerIds, pointerCoords,
xPrecision, yPrecision, mDownTime);
}
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index cf0f63e247a14..4c402dc0202e3 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -318,8 +318,8 @@ status_t InputPublisher::publishKeyEvent(
nsecs_t downTime,
nsecs_t eventTime) {
#if DEBUG_TRANSPORT_ACTIONS
- LOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=%d, "
- "action=%d, flags=%d, keyCode=%d, scanCode=%d, metaState=%d, repeatCount=%d,"
+ LOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, "
+ "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
"downTime=%lld, eventTime=%lld",
mChannel->getName().string(),
deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
@@ -346,6 +346,7 @@ status_t InputPublisher::publishMotionEvent(
int32_t deviceId,
int32_t source,
int32_t action,
+ int32_t flags,
int32_t edgeFlags,
int32_t metaState,
float xOffset,
@@ -358,12 +359,12 @@ status_t InputPublisher::publishMotionEvent(
const int32_t* pointerIds,
const PointerCoords* pointerCoords) {
#if DEBUG_TRANSPORT_ACTIONS
- LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=%d, "
- "action=%d, edgeFlags=%d, metaState=%d, xOffset=%f, yOffset=%f, "
+ LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
+ "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, xOffset=%f, yOffset=%f, "
"xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
"pointerCount=%d",
mChannel->getName().string(),
- deviceId, source, action, edgeFlags, metaState, xOffset, yOffset,
+ deviceId, source, action, flags, edgeFlags, metaState, xOffset, yOffset,
xPrecision, yPrecision, downTime, eventTime, pointerCount);
#endif
@@ -379,6 +380,7 @@ status_t InputPublisher::publishMotionEvent(
}
mSharedMessage->motion.action = action;
+ mSharedMessage->motion.flags = flags;
mSharedMessage->motion.edgeFlags = edgeFlags;
mSharedMessage->motion.metaState = metaState;
mSharedMessage->motion.xOffset = xOffset;
@@ -664,6 +666,7 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
mSharedMessage->deviceId,
mSharedMessage->source,
mSharedMessage->motion.action,
+ mSharedMessage->motion.flags,
mSharedMessage->motion.edgeFlags,
mSharedMessage->motion.metaState,
mSharedMessage->motion.xOffset,
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 3bc21fa296561..952b9747691e6 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -138,6 +138,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
const int32_t deviceId = 1;
const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
const int32_t action = AMOTION_EVENT_ACTION_MOVE;
+ const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
const float xOffset = -10;
@@ -167,7 +168,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
}
}
- status = mPublisher->publishMotionEvent(deviceId, source, action, edgeFlags,
+ status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags,
metaState, xOffset, yOffset, xPrecision, yPrecision,
downTime, sampleEventTimes[0], pointerCount, pointerIds, samplePointerCoords.array());
ASSERT_EQ(OK, status)
@@ -213,6 +214,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
EXPECT_EQ(deviceId, motionEvent->getDeviceId());
EXPECT_EQ(source, motionEvent->getSource());
EXPECT_EQ(action, motionEvent->getAction());
+ EXPECT_EQ(flags, motionEvent->getFlags());
EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
EXPECT_EQ(metaState, motionEvent->getMetaState());
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
@@ -322,12 +324,12 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsErr
int32_t pointerIds[pointerCount] = { 0 };
PointerCoords pointerCoords[pointerCount] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(INVALID_OPERATION, status)
<< "publisher publishMotionEvent should return INVALID_OPERATION because ";
@@ -342,7 +344,7 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha
int32_t pointerIds[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -356,7 +358,7 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater
int32_t pointerIds[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -402,7 +404,7 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEven
PointerCoords pointerCoords[pointerCount];
status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
- 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(OK, status);
status = mPublisher->appendMotionSample(0, pointerCoords);
@@ -419,7 +421,7 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_Ret
PointerCoords pointerCoords[pointerCount];
status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(OK, status);
status = mPublisher->sendDispatchSignal();
@@ -446,7 +448,7 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsE
PointerCoords pointerCoords[pointerCount];
status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
ASSERT_EQ(OK, status);
for (int count = 1;; count++) {
diff --git a/native/android/input.cpp b/native/android/input.cpp
index c79f913237aed..57f0072646705 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -84,6 +84,10 @@ int32_t AMotionEvent_getAction(const AInputEvent* motion_event) {
return static_cast(motion_event)->getAction();
}
+int32_t AMotionEvent_getFlags(const AInputEvent* motion_event) {
+ return static_cast(motion_event)->getFlags();
+}
+
int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event) {
return static_cast(motion_event)->getMetaState();
}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 5b62da44336ee..9da122b6f842f 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -246,6 +246,22 @@ enum {
AMOTION_EVENT_ACTION_POINTER_UP = 6
};
+/*
+ * Motion event flags.
+ */
+enum {
+ /* This flag indicates that the window that received this motion event is partly
+ * or wholly obscured by another visible window above it. This flag is set to true
+ * even if the event did not directly pass through the obscured area.
+ * A security sensitive application can check this flag to identify situations in which
+ * a malicious application may have covered up part of its content for the purpose
+ * of misleading the user or hijacking touches. An appropriate response might be
+ * to drop the suspect touches or to take additional precautions to confirm the user's
+ * actual intent.
+ */
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1,
+};
+
/*
* Motion event edge touch flags.
*/
@@ -395,6 +411,9 @@ int64_t AKeyEvent_getEventTime(const AInputEvent* key_event);
/* Get the combined motion event action code and pointer index. */
int32_t AMotionEvent_getAction(const AInputEvent* motion_event);
+/* Get the motion event flags. */
+int32_t AMotionEvent_getFlags(const AInputEvent* motion_event);
+
/* Get the state of any meta / modifier keys that were in effect when the
* event was generated. */
int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event);
diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java
index 8da0cf110f1fe..dbc59ef9dfd54 100644
--- a/services/java/com/android/server/InputWindow.java
+++ b/services/java/com/android/server/InputWindow.java
@@ -34,9 +34,17 @@ public final class InputWindow {
// Dispatching timeout.
public long dispatchingTimeoutNanos;
- // Window frame position.
+ // Window frame area.
public int frameLeft;
public int frameTop;
+ public int frameRight;
+ public int frameBottom;
+
+ // Window visible frame area.
+ public int visibleFrameLeft;
+ public int visibleFrameTop;
+ public int visibleFrameRight;
+ public int visibleFrameBottom;
// Window touchable area.
public int touchableAreaLeft;
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3841f75c7cc52..0bc9b615c0324 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5218,6 +5218,14 @@ public class WindowManagerService extends IWindowManager.Stub
final Rect frame = child.mFrame;
inputWindow.frameLeft = frame.left;
inputWindow.frameTop = frame.top;
+ inputWindow.frameRight = frame.right;
+ inputWindow.frameBottom = frame.bottom;
+
+ final Rect visibleFrame = child.mVisibleFrame;
+ inputWindow.visibleFrameLeft = visibleFrame.left;
+ inputWindow.visibleFrameTop = visibleFrame.top;
+ inputWindow.visibleFrameRight = visibleFrame.right;
+ inputWindow.visibleFrameBottom = visibleFrame.bottom;
switch (child.mTouchableInsets) {
default:
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index a237ee94bfb3d..43186816317ef 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -169,6 +169,12 @@ static struct {
jfieldID dispatchingTimeoutNanos;
jfieldID frameLeft;
jfieldID frameTop;
+ jfieldID frameRight;
+ jfieldID frameBottom;
+ jfieldID visibleFrameLeft;
+ jfieldID visibleFrameTop;
+ jfieldID visibleFrameRight;
+ jfieldID visibleFrameBottom;
jfieldID touchableAreaLeft;
jfieldID touchableAreaTop;
jfieldID touchableAreaRight;
@@ -283,6 +289,12 @@ private:
nsecs_t dispatchingTimeout;
int32_t frameLeft;
int32_t frameTop;
+ int32_t frameRight;
+ int32_t frameBottom;
+ int32_t visibleFrameLeft;
+ int32_t visibleFrameTop;
+ int32_t visibleFrameRight;
+ int32_t visibleFrameBottom;
int32_t touchableAreaLeft;
int32_t touchableAreaTop;
int32_t touchableAreaRight;
@@ -294,10 +306,8 @@ private:
int32_t ownerPid;
int32_t ownerUid;
- inline bool touchableAreaContainsPoint(int32_t x, int32_t y) {
- return x >= touchableAreaLeft && x <= touchableAreaRight
- && y >= touchableAreaTop && y <= touchableAreaBottom;
- }
+ bool visibleFrameIntersects(const InputWindow* other) const;
+ bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
};
struct InputApplication {
@@ -370,9 +380,13 @@ private:
// Focus tracking for touch.
bool mTouchDown;
InputWindow* mTouchedWindow; // primary target for current down
+ bool mTouchedWindowIsObscured; // true if other windows may obscure the target
Vector mTouchedWallpaperWindows; // wallpaper targets
-
- Vector mTempTouchedOutsideWindows; // temporary outside touch targets
+ struct OutsideTarget {
+ InputWindow* window;
+ bool obscured;
+ };
+ Vector mTempTouchedOutsideTargets; // temporary outside touch targets
Vector > mTempTouchedWallpaperChannels; // temporary wallpaper targets
// Focused application.
@@ -391,6 +405,7 @@ private:
int32_t waitForTouchedWindowLd(MotionEvent* motionEvent, uint32_t policyFlags,
int32_t injectorPid, int32_t injectorUid,
Vector& outTargets, InputWindow*& outTouchedWindow);
+ bool isWindowObscuredLocked(const InputWindow* window);
void releaseTouchedWindowLd();
@@ -1117,6 +1132,18 @@ bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj,
gInputWindowClassInfo.frameLeft);
jint frameTop = env->GetIntField(windowObj,
gInputWindowClassInfo.frameTop);
+ jint frameRight = env->GetIntField(windowObj,
+ gInputWindowClassInfo.frameRight);
+ jint frameBottom = env->GetIntField(windowObj,
+ gInputWindowClassInfo.frameBottom);
+ jint visibleFrameLeft = env->GetIntField(windowObj,
+ gInputWindowClassInfo.visibleFrameLeft);
+ jint visibleFrameTop = env->GetIntField(windowObj,
+ gInputWindowClassInfo.visibleFrameTop);
+ jint visibleFrameRight = env->GetIntField(windowObj,
+ gInputWindowClassInfo.visibleFrameRight);
+ jint visibleFrameBottom = env->GetIntField(windowObj,
+ gInputWindowClassInfo.visibleFrameBottom);
jint touchableAreaLeft = env->GetIntField(windowObj,
gInputWindowClassInfo.touchableAreaLeft);
jint touchableAreaTop = env->GetIntField(windowObj,
@@ -1144,6 +1171,12 @@ bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj,
outWindow.dispatchingTimeout = dispatchingTimeoutNanos;
outWindow.frameLeft = frameLeft;
outWindow.frameTop = frameTop;
+ outWindow.frameRight = frameRight;
+ outWindow.frameBottom = frameBottom;
+ outWindow.visibleFrameLeft = visibleFrameLeft;
+ outWindow.visibleFrameTop = visibleFrameTop;
+ outWindow.visibleFrameRight = visibleFrameRight;
+ outWindow.visibleFrameBottom = visibleFrameBottom;
outWindow.touchableAreaLeft = touchableAreaLeft;
outWindow.touchableAreaTop = touchableAreaTop;
outWindow.touchableAreaRight = touchableAreaRight;
@@ -1417,11 +1450,12 @@ int32_t NativeInputManager::waitForTouchedWindowLd(MotionEvent* motionEvent, uin
/* Case 1: ACTION_DOWN */
InputWindow* newTouchedWindow = NULL;
- mTempTouchedOutsideWindows.clear();
+ mTempTouchedOutsideTargets.clear();
int32_t x = int32_t(motionEvent->getX(0));
int32_t y = int32_t(motionEvent->getY(0));
InputWindow* topErrorWindow = NULL;
+ bool obscured = false;
// Traverse windows from front to back to find touched window and outside targets.
size_t numWindows = mWindows.size();
@@ -1442,13 +1476,17 @@ int32_t NativeInputManager::waitForTouchedWindowLd(MotionEvent* motionEvent, uin
if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
if (! screenWasOff || flags & FLAG_TOUCHABLE_WHEN_WAKING) {
newTouchedWindow = window;
+ obscured = isWindowObscuredLocked(window);
}
break; // found touched window, exit window loop
}
}
if (flags & FLAG_WATCH_OUTSIDE_TOUCH) {
- mTempTouchedOutsideWindows.push(window);
+ OutsideTarget outsideTarget;
+ outsideTarget.window = window;
+ outsideTarget.obscured = isWindowObscuredLocked(window);
+ mTempTouchedOutsideTargets.push(outsideTarget);
}
}
}
@@ -1501,6 +1539,7 @@ int32_t NativeInputManager::waitForTouchedWindowLd(MotionEvent* motionEvent, uin
releaseTouchedWindowLd();
mTouchedWindow = newTouchedWindow;
+ mTouchedWindowIsObscured = obscured;
if (newTouchedWindow->hasWallpaper) {
mTouchedWallpaperWindows.appendVector(mWallpaperWindows);
@@ -1557,21 +1596,31 @@ int32_t NativeInputManager::waitForTouchedWindowLd(MotionEvent* motionEvent, uin
if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED) {
size_t numWallpaperWindows = mTouchedWallpaperWindows.size();
for (size_t i = 0; i < numWallpaperWindows; i++) {
- addTarget(mTouchedWallpaperWindows[i], 0, 0, outTargets);
+ addTarget(mTouchedWallpaperWindows[i],
+ InputTarget::FLAG_WINDOW_IS_OBSCURED, 0, outTargets);
}
- size_t numOutsideWindows = mTempTouchedOutsideWindows.size();
- for (size_t i = 0; i < numOutsideWindows; i++) {
- addTarget(mTempTouchedOutsideWindows[i], InputTarget::FLAG_OUTSIDE, 0, outTargets);
+ size_t numOutsideTargets = mTempTouchedOutsideTargets.size();
+ for (size_t i = 0; i < numOutsideTargets; i++) {
+ const OutsideTarget& outsideTarget = mTempTouchedOutsideTargets[i];
+ int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;
+ if (outsideTarget.obscured) {
+ outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ }
+ addTarget(outsideTarget.window, outsideTargetFlags, 0, outTargets);
}
- addTarget(mTouchedWindow, InputTarget::FLAG_SYNC,
+ int32_t targetFlags = InputTarget::FLAG_SYNC;
+ if (mTouchedWindowIsObscured) {
+ targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+ }
+ addTarget(mTouchedWindow, targetFlags,
anrTimer.getTimeSpentWaitingForApplication(), outTargets);
outTouchedWindow = mTouchedWindow;
} else {
outTouchedWindow = NULL;
}
- mTempTouchedOutsideWindows.clear();
+ mTempTouchedOutsideTargets.clear();
// Check injection permission once and for all.
if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
@@ -1616,6 +1665,7 @@ int32_t NativeInputManager::waitForTouchedWindowLd(MotionEvent* motionEvent, uin
void NativeInputManager::releaseTouchedWindowLd() {
mTouchedWindow = NULL;
+ mTouchedWindowIsObscured = false;
mTouchedWallpaperWindows.clear();
}
@@ -1661,6 +1711,20 @@ bool NativeInputManager::checkInjectionPermission(const InputWindow* window,
return true;
}
+bool NativeInputManager::isWindowObscuredLocked(const InputWindow* window) {
+ size_t numWindows = mWindows.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const InputWindow* other = & mWindows.itemAt(i);
+ if (other == window) {
+ break;
+ }
+ if (other->visible && window->visibleFrameIntersects(other)) {
+ return true;
+ }
+ }
+ return false;
+}
+
int32_t NativeInputManager::waitForKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
int32_t injectorPid, int32_t injectorUid, Vector& outTargets) {
#if DEBUG_INPUT_DISPATCHER_POLICY
@@ -1935,12 +1999,17 @@ void NativeInputManager::dumpDispatchStateLd(String8& dump) {
for (size_t i = 0; i < mWindows.size(); i++) {
dump.appendFormat(" windows[%d]: '%s', paused=%d, hasFocus=%d, hasWallpaper=%d, "
"visible=%d, flags=0x%08x, type=0x%08x, "
- "frame=[%d,%d], touchableArea=[%d,%d][%d,%d], "
+ "frame=[%d,%d][%d,%d], "
+ "visibleFrame=[%d,%d][%d,%d], "
+ "touchableArea=[%d,%d][%d,%d], "
"ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
i, mWindows[i].inputChannel->getName().string(),
mWindows[i].paused, mWindows[i].hasFocus, mWindows[i].hasWallpaper,
mWindows[i].visible, mWindows[i].layoutParamsFlags, mWindows[i].layoutParamsType,
mWindows[i].frameLeft, mWindows[i].frameTop,
+ mWindows[i].frameRight, mWindows[i].frameBottom,
+ mWindows[i].visibleFrameLeft, mWindows[i].visibleFrameTop,
+ mWindows[i].visibleFrameRight, mWindows[i].visibleFrameBottom,
mWindows[i].touchableAreaLeft, mWindows[i].touchableAreaTop,
mWindows[i].touchableAreaRight, mWindows[i].touchableAreaBottom,
mWindows[i].ownerPid, mWindows[i].ownerUid,
@@ -1955,6 +2024,20 @@ void NativeInputManager::dumpDispatchStateLd(String8& dump) {
// ----------------------------------------------------------------------------
+bool NativeInputManager::InputWindow::visibleFrameIntersects(const InputWindow* other) const {
+ return visibleFrameRight > other->visibleFrameLeft
+ && visibleFrameLeft < other->visibleFrameRight
+ && visibleFrameBottom > other->visibleFrameTop
+ && visibleFrameTop < other->visibleFrameBottom;
+}
+
+bool NativeInputManager::InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const {
+ return x >= touchableAreaLeft && x <= touchableAreaRight
+ && y >= touchableAreaTop && y <= touchableAreaBottom;
+}
+
+// ----------------------------------------------------------------------------
+
NativeInputManager::ANRTimer::ANRTimer() :
mBudget(APPLICATION), mStartTime(now()), mFrozen(false), mPausedWindow(NULL) {
}
@@ -2507,6 +2590,24 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz,
"frameTop", "I");
+ GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz,
+ "frameRight", "I");
+
+ GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
+ "frameBottom", "I");
+
+ GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz,
+ "visibleFrameLeft", "I");
+
+ GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz,
+ "visibleFrameTop", "I");
+
+ GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz,
+ "visibleFrameRight", "I");
+
+ GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz,
+ "visibleFrameBottom", "I");
+
GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz,
"touchableAreaLeft", "I");