diff options
-rw-r--r-- | api/current.xml | 105 | ||||
-rw-r--r-- | core/java/android/view/MotionEvent.java | 40 | ||||
-rw-r--r-- | core/java/android/view/View.java | 88 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 4 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerPolicy.java | 2 | ||||
-rw-r--r-- | core/jni/android_view_MotionEvent.cpp | 8 | ||||
-rwxr-xr-x | core/res/res/values/attrs.xml | 6 | ||||
-rw-r--r-- | core/res/res/values/public.xml | 1 | ||||
-rw-r--r-- | include/ui/Input.h | 9 | ||||
-rw-r--r-- | include/ui/InputDispatcher.h | 28 | ||||
-rw-r--r-- | include/ui/InputTransport.h | 2 | ||||
-rw-r--r-- | libs/ui/Input.cpp | 2 | ||||
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 38 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 4 | ||||
-rw-r--r-- | libs/ui/InputTransport.cpp | 13 | ||||
-rw-r--r-- | libs/ui/tests/InputPublisherAndConsumer_test.cpp | 18 | ||||
-rw-r--r-- | native/android/input.cpp | 4 | ||||
-rw-r--r-- | native/include/android/input.h | 19 | ||||
-rw-r--r-- | services/java/com/android/server/InputWindow.java | 10 | ||||
-rw-r--r-- | services/java/com/android/server/WindowManagerService.java | 8 | ||||
-rw-r--r-- | services/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 05c3159..4da6c4b 100644 --- a/api/current.xml +++ b/api/current.xml @@ -5861,17 +5861,6 @@ visibility="public" > </field> -<field name="kraken_resource_pad61" - type="int" - transient="false" - volatile="false" - value="16843460" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="kraken_resource_pad7" type="int" transient="false" @@ -8248,6 +8237,17 @@ visibility="public" > </field> +<field name="securityMode" + type="int" + transient="false" + volatile="false" + value="16843460" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="seekBarStyle" type="int" transient="false" @@ -181733,6 +181733,17 @@ visibility="public" > </method> +<method name="getFlags" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getHistoricalEventTime" return="long" abstract="false" @@ -182370,6 +182381,8 @@ </parameter> <parameter name="source" type="int"> </parameter> +<parameter name="flags" type="int"> +</parameter> </method> <method name="obtain" return="android.view.MotionEvent" @@ -182826,6 +182839,17 @@ visibility="public" > </field> +<field name="FLAG_WINDOW_MAY_BE_OBSCURED" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="MotionEvent.PointerCoords" extends="java.lang.Object" @@ -186006,6 +186030,17 @@ visibility="public" > </method> +<method name="getSecurityMode" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getSolidColor" return="int" abstract="false" @@ -186836,6 +186871,19 @@ <parameter name="canvas" type="android.graphics.Canvas"> </parameter> </method> +<method name="onFilterTouchEventForSecurity" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="event" type="android.view.MotionEvent"> +</parameter> +</method> <method name="onFinishInflate" return="void" abstract="false" @@ -188127,6 +188175,19 @@ <parameter name="fadeScrollbars" type="boolean"> </parameter> </method> +<method name="setSecurityMode" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="securityMode" type="int"> +</parameter> +</method> <method name="setSelected" return="void" abstract="false" @@ -188907,6 +188968,28 @@ visibility="public" > </field> +<field name="SECURITY_MODE_FILTER_TOUCHES_WHEN_OBSCURED" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="SECURITY_MODE_NORMAL" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="SELECTED_STATE_SET" type="int[]" transient="false" diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 74318ba..78b9b5d 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -30,6 +30,7 @@ import android.os.SystemClock; */ public final class MotionEvent extends InputEvent implements Parcelable { private static final long MS_PER_NS = 1000000; + private static final boolean TRACK_RECYCLED_LOCATION = false; /** * Bit mask of the parts of the action code that are the action itself. @@ -155,7 +156,17 @@ public final class MotionEvent extends InputEvent implements Parcelable { @Deprecated public static final int ACTION_POINTER_ID_SHIFT = 8; - private static final boolean TRACK_RECYCLED_LOCATION = false; + /** + * 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. + */ + public static final int FLAG_WINDOW_IS_OBSCURED = 0x1; /** * Flag indicating the motion event intersected the top edge of the screen. @@ -251,6 +262,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { private float mYPrecision; private int mEdgeFlags; private int mMetaState; + private int mFlags; private int mNumPointers; private int mNumSamples; @@ -338,20 +350,22 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @param deviceId The id for the device that this event came from. An id of * zero indicates that the event didn't come from a physical device; other * numbers are arbitrary and you shouldn't depend on the values. - * @param edgeFlags A bitfield indicating which edges, if any, where touched by this + * @param edgeFlags A bitfield indicating which edges, if any, were touched by this * MotionEvent. * @param source The source of this event. + * @param flags The motion event flags. */ static public MotionEvent obtain(long downTime, long eventTime, int action, int pointers, int[] pointerIds, PointerCoords[] pointerCoords, int metaState, float xPrecision, float yPrecision, int deviceId, - int edgeFlags, int source) { + int edgeFlags, int source, int flags) { MotionEvent ev = obtain(pointers, 1); ev.mDeviceId = deviceId; ev.mSource = source; ev.mEdgeFlags = edgeFlags; ev.mDownTimeNano = downTime * MS_PER_NS; ev.mAction = action; + ev.mFlags = flags; ev.mMetaState = metaState; ev.mXOffset = 0; ev.mYOffset = 0; @@ -401,7 +415,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @param deviceId The id for the device that this event came from. An id of * zero indicates that the event didn't come from a physical device; other * numbers are arbitrary and you shouldn't depend on the values. - * @param edgeFlags A bitfield indicating which edges, if any, where touched by this + * @param edgeFlags A bitfield indicating which edges, if any, were touched by this * MotionEvent. */ static public MotionEvent obtain(long downTime, long eventTime, int action, @@ -413,6 +427,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { ev.mEdgeFlags = edgeFlags; ev.mDownTimeNano = downTime * MS_PER_NS; ev.mAction = action; + ev.mFlags = 0; ev.mMetaState = metaState; ev.mXOffset = 0; ev.mYOffset = 0; @@ -462,7 +477,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @param deviceId The id for the device that this event came from. An id of * zero indicates that the event didn't come from a physical device; other * numbers are arbitrary and you shouldn't depend on the values. - * @param edgeFlags A bitfield indicating which edges, if any, where touched by this + * @param edgeFlags A bitfield indicating which edges, if any, were touched by this * MotionEvent. * * @deprecated Use {@link #obtain(long, long, int, float, float, float, float, int, float, float, int, int)} @@ -509,6 +524,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { ev.mEdgeFlags = o.mEdgeFlags; ev.mDownTimeNano = o.mDownTimeNano; ev.mAction = o.mAction; + ev.mFlags = o.mFlags; ev.mMetaState = o.mMetaState; ev.mXOffset = o.mXOffset; ev.mYOffset = o.mYOffset; @@ -540,6 +556,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { ev.mEdgeFlags = o.mEdgeFlags; ev.mDownTimeNano = o.mDownTimeNano; ev.mAction = o.mAction; + o.mFlags = o.mFlags; ev.mMetaState = o.mMetaState; ev.mXOffset = o.mXOffset; ev.mYOffset = o.mYOffset; @@ -651,6 +668,15 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** + * 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 7332c16..fe003a4 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. * </p> * + * <a name="Security"></a> + * <h3>Security</h3> + * <p> + * 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. + * </p><p> + * 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. + * </p><p> + * 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}. + * </p> + * * @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... /** * <p>This view doesn't show fading edges.</p> @@ -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; @@ -3816,6 +3885,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * 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. * * @param event The motion event to be dispatched. diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 7159929..28bed3a 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 659f9cd..76701a9 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 fe247e8..93fd54f 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 1130b69..13c3e7e 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1274,6 +1274,12 @@ be saved. --> <attr name="saveEnabled" format="boolean" /> + <!-- Specifies whether to filter touches when the view's window is obscured by + another visible window. When set to true, the view will not receive touches + whenever a toast, dialog or other window appears above the view's window. + Refer to the {@link android.view.View} security documentation for more details. --> + <attr name="filterTouchesWhenObscured" format="boolean" /> + <!-- Defines the quality of translucent drawing caches. This property is used only when the drawing cache is enabled and translucent. The default value is auto. --> <attr name="drawingCacheQuality"> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 86e79c8..28a7cca 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1254,6 +1254,7 @@ <public type="attr" name="overscrollMode" id="0x010102c1" /> <public type="attr" name="overscrollHeader" id="0x010102c2" /> <public type="attr" name="overscrollFooter" id="0x010102c3" /> + <public type="attr" name="filterTouchesWhenObscured" id="0x010102c4" /> <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" /> diff --git a/include/ui/Input.h b/include/ui/Input.h index 3fa825f..b587e94 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 aed4fa1..711a658 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 31ec701..82831e2 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 4973cd8..811edaf 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 886c785..e5b7f28 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<const KeyEvent*>(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<const MotionEvent*>(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 8ffb48d..d57b38c 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 cf0f63e..4c402dc 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 3bc21fa..952b974 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 c79f913..57f0072 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<const MotionEvent*>(motion_event)->getAction(); } +int32_t AMotionEvent_getFlags(const AInputEvent* motion_event) { + return static_cast<const MotionEvent*>(motion_event)->getFlags(); +} + int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event) { return static_cast<const MotionEvent*>(motion_event)->getMetaState(); } diff --git a/native/include/android/input.h b/native/include/android/input.h index 5b62da4..9da122b 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -247,6 +247,22 @@ enum { }; /* + * 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. */ enum { @@ -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 8da0cf1..dbc59ef 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 3841f75..0bc9b61 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 a237ee9..4318681 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<InputWindow*> mTouchedWallpaperWindows; // wallpaper targets - - Vector<InputWindow*> mTempTouchedOutsideWindows; // temporary outside touch targets + struct OutsideTarget { + InputWindow* window; + bool obscured; + }; + Vector<OutsideTarget> mTempTouchedOutsideTargets; // temporary outside touch targets Vector<sp<InputChannel> > 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<InputTarget>& 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<InputTarget>& 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"); |