diff options
Diffstat (limited to 'core')
-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 |
7 files changed, 141 insertions, 8 deletions
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" /> |