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
This commit is contained in:
Jeff Brown
2010-09-01 17:01:00 -07:00
parent c0b4f6d30d
commit 85a3176704
21 changed files with 467 additions and 73 deletions

View File

@@ -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;
@@ -650,6 +667,15 @@ public final class MotionEvent extends InputEvent implements Parcelable {
return (mAction & ACTION_POINTER_INDEX_MASK) >> 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++) {

View File

@@ -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;
@@ -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.
*

View File

@@ -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();

View File

@@ -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;