Merge "Add new MotionEvent flag for partially obscured windows." into mnc-dev
diff --git a/include/input/Input.h b/include/input/Input.h
index 617175b..82fc659 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -45,6 +45,19 @@
 };
 
 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_PARTIALLY_OBSCURED = 0x2,
+
     /* Motion event is inconsistent with previously sent motion events. */
     AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
 };
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 0fba1bf..c9e876f 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -1225,6 +1225,8 @@
                     int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
                     if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
                         outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+                    } else if (isWindowObscuredLocked(windowHandle)) {
+                        outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
                     }
 
                     mTempTouchState.addOrUpdateWindow(
@@ -1262,6 +1264,8 @@
         }
         if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
             targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+        } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
+            targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
         }
 
         // Update hover state.
@@ -1437,6 +1441,7 @@
                                 == InputWindowInfo::TYPE_WALLPAPER) {
                     mTempTouchState.addOrUpdateWindow(windowHandle,
                             InputTarget::FLAG_WINDOW_IS_OBSCURED
+                                    | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED
                                     | InputTarget::FLAG_DISPATCH_AS_IS,
                             BitSet32(0));
                 }
@@ -1631,6 +1636,27 @@
     return false;
 }
 
+
+bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
+    int32_t displayId = windowHandle->getInfo()->displayId;
+    const InputWindowInfo* windowInfo = windowHandle->getInfo();
+    size_t numWindows = mWindowHandles.size();
+    for (size_t i = 0; i < numWindows; i++) {
+        sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+        if (otherHandle == windowHandle) {
+            break;
+        }
+
+        const InputWindowInfo* otherInfo = otherHandle->getInfo();
+        if (otherInfo->displayId == displayId
+                && otherInfo->visible && !otherInfo->isTrustedOverlay()
+                && otherInfo->overlaps(windowInfo)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
         const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
         const char* targetType) {
@@ -1905,6 +1931,9 @@
         if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
             dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
         }
+        if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {
+            dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+        }
 
         if (!connection->inputState.trackMotion(motionEntry,
                 dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 98355c6..1c054f5 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -89,7 +89,7 @@
         /* This flag indicates that the event is being delivered to a foreground application. */
         FLAG_FOREGROUND = 1 << 0,
 
-        /* This flag indicates that the target of a MotionEvent is partly or wholly
+        /* This flag indicates that the MotionEvent falls within the area of the target
          * 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 = 1 << 1,
@@ -139,6 +139,12 @@
                 | FLAG_DISPATCH_AS_HOVER_EXIT
                 | FLAG_DISPATCH_AS_SLIPPERY_EXIT
                 | FLAG_DISPATCH_AS_SLIPPERY_ENTER,
+
+        /* 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_PARTIALLY_OBSCURED. */
+        FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
+
     };
 
     // The input channel to be targeted.
@@ -1048,6 +1054,7 @@
             const InjectionState* injectionState);
     bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
             int32_t x, int32_t y) const;
+    bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const;
     String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle);
 
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index fda3ffa..1b913c5 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -36,14 +36,16 @@
 }
 
 bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
-    return x >= frameLeft && x <= frameRight
-            && y >= frameTop && y <= frameBottom;
+    return x >= frameLeft && x < frameRight
+            && y >= frameTop && y < frameBottom;
 }
 
 bool InputWindowInfo::isTrustedOverlay() const {
     return layoutParamsType == TYPE_INPUT_METHOD
             || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
             || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
+            || layoutParamsType == TYPE_STATUS_BAR
+            || layoutParamsType == TYPE_NAVIGATION_BAR
             || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
 }
 
@@ -51,6 +53,11 @@
     return layoutParamsFlags & FLAG_SPLIT_TOUCH;
 }
 
+bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
+    return frameLeft < other->frameRight && frameRight > other->frameLeft
+            && frameTop < other->frameBottom && frameBottom > other->frameTop;
+}
+
 
 // --- InputWindowHandle ---
 
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 42457ce..0ac7fce 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -146,6 +146,8 @@
     bool isTrustedOverlay() const;
 
     bool supportsSplitTouch() const;
+
+    bool overlaps(const InputWindowInfo* other) const;
 };