resolved conflicts for merge of a05088c1 to master

Change-Id: I7973f9f28586dec9b9659f8f662f40db7997a521
diff --git a/api/current.xml b/api/current.xml
index 3319a98..bfbeaa2 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4200,6 +4200,17 @@
  visibility="public"
 >
 </field>
+<field name="filterTouchesWhenObscured"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843460"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="finishOnCloseSystemDialogs"
  type="int"
  transient="false"
@@ -6158,50 +6169,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_pad62"
- type="int"
- transient="false"
- volatile="false"
- value="16843459"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad63"
- type="int"
- transient="false"
- volatile="false"
- value="16843458"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad64"
- type="int"
- transient="false"
- volatile="false"
- value="16843457"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad7"
  type="int"
  transient="false"
@@ -191959,6 +191926,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"
@@ -192596,6 +192574,8 @@
 </parameter>
 <parameter name="source" type="int">
 </parameter>
+<parameter name="flags" type="int">
+</parameter>
 </method>
 <method name="obtain"
  return="android.view.MotionEvent"
@@ -193052,6 +193032,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_WINDOW_IS_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"
@@ -195842,6 +195833,17 @@
  visibility="public"
 >
 </method>
+<method name="getFilterTouchesWhenObscured"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFocusables"
  return="java.util.ArrayList&lt;android.view.View&gt;"
  abstract="false"
@@ -197273,6 +197275,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"
@@ -198170,6 +198185,19 @@
 <parameter name="length" type="int">
 </parameter>
 </method>
+<method name="setFilterTouchesWhenObscured"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
 <method name="setFocusable"
  return="void"
  abstract="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 @@
  */
 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 @@
     @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 @@
     private float mYPrecision;
     private int mEdgeFlags;
     private int mMetaState;
+    private int mFlags;
     
     private int mNumPointers;
     private int mNumSamples;
@@ -338,20 +350,22 @@
      * @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 @@
      * @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 @@
         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 @@
      * @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 @@
         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 @@
         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 @@
     }
 
     /**
+     * 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 @@
 
 
     /**
-     * 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 @@
         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 @@
         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 f8d79e5..5d258967 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -545,6 +545,28 @@
  * 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
@@ -553,6 +575,7 @@
  * @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
@@ -714,7 +737,14 @@
      */
     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>
@@ -2171,6 +2201,12 @@
                         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;
@@ -3539,6 +3575,35 @@
         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);
+    }
 
     /**
      * Indicates whether the entire hierarchy under this view will save its
@@ -3990,6 +4055,10 @@
      * @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;
@@ -3998,6 +4067,23 @@
     }
 
     /**
+     * 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 363ccd6..c8b26ef 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -868,12 +868,16 @@
      */
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (!onFilterTouchEventForSecurity(ev)) {
+            return false;
+        }
+
         if ((mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS) {
             if (mSplitMotionTargets == null) {
                 mSplitMotionTargets = new SplitMotionTargets();
             }
             return dispatchSplitTouchEvent(ev);
-        }
+	}
 
         final int action = ev.getAction();
         final float xf = ev.getX();
@@ -4471,7 +4475,7 @@
             return MotionEvent.obtain(downTime, ev.getEventTime(),
                     action, pointerCount, mPointerIds, mPointerCoords, ev.getMetaState(),
                     ev.getXPrecision(), ev.getYPrecision(), ev.getDeviceId(), ev.getEdgeFlags(),
-                    ev.getSource());
+                    ev.getSource(), ev.getFlags());
         }
 
         static class TargetInfo {
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 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 @@
     jfieldID mYPrecision;
     jfieldID mEdgeFlags;
     jfieldID mMetaState;
+    jfieldID mFlags;
     jfieldID mNumPointers;
     jfieldID mNumSamples;
     jfieldID mPointerIdentifiers;
@@ -91,6 +92,8 @@
             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 @@
     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 @@
         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 @@
             "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 7b8d427..b476b44 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1345,6 +1345,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 8594027..7bb56bd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1251,6 +1251,8 @@
   <public type="attr" name="logo" id="0x010102be" />
   <public type="attr" name="xlargeScreens" id="0x010102bf" />
   <public type="attr" name="immersive" id="0x010102c0" />
+  <public type="attr" name="filterTouchesWhenObscured" id="0x010102c4" />
+
   <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
 
   <public-padding type="id" name="kraken_resource_pad" end="0x01020040" />
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 @@
 
     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 @@
 
     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 @@
             int32_t deviceId,
             int32_t source,
             int32_t action,
+            int32_t flags,
             int32_t edgeFlags,
             int32_t metaState,
             float xOffset,
@@ -370,6 +378,7 @@
 
 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 @@
          * 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 @@
             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 @@
             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 @@
         int32_t source;
         uint32_t policyFlags;
         int32_t action;
+        int32_t flags;
         int32_t metaState;
         int32_t edgeFlags;
         float xPrecision;
@@ -458,7 +469,8 @@
                 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 {
             int32_t action;
+            int32_t flags;
             int32_t metaState;
             int32_t edgeFlags;
             nsecs_t downTime;
@@ -218,6 +219,7 @@
             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 @@
         int32_t deviceId,
         int32_t source,
         int32_t action,
+        int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
         float xOffset,
@@ -142,6 +143,7 @@
         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::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 @@
     }
     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 @@
     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 @@
 
         // 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 @@
 
         // 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::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 @@
 
         // 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 @@
     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 @@
 
     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 @@
 
         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::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 @@
     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 @@
     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 @@
     } // 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 @@
         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 @@
         int32_t deviceId,
         int32_t source,
         int32_t action,
+        int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
         float xOffset,
@@ -358,12 +359,12 @@
         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 @@
     }
 
     mSharedMessage->motion.action = action;
+    mSharedMessage->motion.flags = flags;
     mSharedMessage->motion.edgeFlags = edgeFlags;
     mSharedMessage->motion.metaState = metaState;
     mSharedMessage->motion.xOffset = xOffset;
@@ -664,6 +666,7 @@
             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 @@
     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 @@
         }
     }
 
-    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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 };
 
 /*
+ * 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 @@
 /* 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 @@
     // 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 79bde7c..2ab8091 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5208,6 +5208,14 @@
                 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 @@
     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 @@
         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 @@
         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 @@
     // 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 @@
     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 @@
                     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 @@
             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 @@
             /* 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 @@
                         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 @@
             releaseTouchedWindowLd();
 
             mTouchedWindow = newTouchedWindow;
+            mTouchedWindowIsObscured = obscured;
 
             if (newTouchedWindow->hasWallpaper) {
                 mTouchedWallpaperWindows.appendVector(mWallpaperWindows);
@@ -1557,21 +1596,31 @@
     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 @@
 
 void NativeInputManager::releaseTouchedWindowLd() {
     mTouchedWindow = NULL;
+    mTouchedWindowIsObscured = false;
     mTouchedWallpaperWindows.clear();
 }
 
@@ -1661,6 +1711,20 @@
     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 @@
     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 @@
 
 // ----------------------------------------------------------------------------
 
+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 @@
     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");