Make secure views tolerate IME overlays.

Change-Id: I3cf09b9d91045f4d9c558b4aace482a7b0bbd3d8
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index cc160129..47c5326 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -212,8 +212,15 @@
     int32_t ownerPid;
     int32_t ownerUid;
 
-    bool visibleFrameIntersects(const InputWindow* other) const;
     bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
+    bool frameContainsPoint(int32_t x, int32_t y) const;
+
+    /* Returns true if the window is of a trusted type that is allowed to silently
+     * overlay other windows for the purpose of implementing the secure views feature.
+     * Trusted overlays, such as IME windows, can partly obscure other windows without causing
+     * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
+     */
+    bool isTrustedOverlay() const;
 };
 
 
@@ -962,7 +969,7 @@
     bool shouldPokeUserActivityForCurrentInputTargetsLocked();
     void pokeUserActivityLocked(nsecs_t eventTime, int32_t eventType);
     bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState);
-    bool isWindowObscuredLocked(const InputWindow* window);
+    bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const;
     bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
     String8 getApplicationWindowLabelLocked(const InputApplication* application,
             const InputWindow* window);
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index aa54f82..fe8555d 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -134,18 +134,21 @@
 
 // --- InputWindow ---
 
-bool InputWindow::visibleFrameIntersects(const InputWindow* other) const {
-    return visibleFrameRight > other->visibleFrameLeft
-        && visibleFrameLeft < other->visibleFrameRight
-        && visibleFrameBottom > other->visibleFrameTop
-        && visibleFrameTop < other->visibleFrameBottom;
-}
-
 bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const {
     return x >= touchableAreaLeft && x <= touchableAreaRight
             && y >= touchableAreaTop && y <= touchableAreaBottom;
 }
 
+bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
+    return x >= frameLeft && x <= frameRight
+            && y >= frameTop && y <= frameBottom;
+}
+
+bool InputWindow::isTrustedOverlay() const {
+    return layoutParamsType == TYPE_INPUT_METHOD
+            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG;
+}
+
 
 // --- InputDispatcher ---
 
@@ -1053,8 +1056,12 @@
 
                 if (maskedAction == AMOTION_EVENT_ACTION_DOWN
                         && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
-                    mTempTouchState.addOrUpdateWindow(window,
-                            InputTarget::FLAG_OUTSIDE, BitSet32(0));
+                    int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;
+                    if (isWindowObscuredAtPointLocked(window, x, y)) {
+                        outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+                    }
+
+                    mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));
                 }
             }
         }
@@ -1083,10 +1090,6 @@
             // (May be NULL which is why we put this code block before the next check.)
             newTouchedWindow = mTempTouchState.getFirstForegroundWindow();
         }
-        int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
-        if (isSplit) {
-            targetFlags |= InputTarget::FLAG_SPLIT;
-        }
 
         // If we did not find a touched window then fail.
         if (! newTouchedWindow) {
@@ -1106,6 +1109,15 @@
             goto Failed;
         }
 
+        // Set target flags.
+        int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
+        if (isSplit) {
+            targetFlags |= InputTarget::FLAG_SPLIT;
+        }
+        if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+            targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+        }
+
         // Update the temporary touch state.
         BitSet32 pointerIds;
         if (isSplit) {
@@ -1186,23 +1198,13 @@
             for (size_t i = 0; i < mWindows.size(); i++) {
                 const InputWindow* window = & mWindows[i];
                 if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
-                    mTempTouchState.addOrUpdateWindow(window, 0, BitSet32(0));
+                    mTempTouchState.addOrUpdateWindow(window,
+                            InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0));
                 }
             }
         }
     }
 
-    // If a touched window has been obscured at any point during the touch gesture, set
-    // the appropriate flag so we remember it for the entire gesture.
-    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
-        TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);
-        if ((touchedWindow.targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) == 0) {
-            if (isWindowObscuredLocked(touchedWindow.window)) {
-                touchedWindow.targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
-            }
-        }
-    }
-
     // Success!  Output targets.
     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
 
@@ -1326,14 +1328,15 @@
     return true;
 }
 
-bool InputDispatcher::isWindowObscuredLocked(const InputWindow* window) {
+bool InputDispatcher::isWindowObscuredAtPointLocked(
+        const InputWindow* window, int32_t x, int32_t y) const {
     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)) {
+        if (other->visible && ! other->isTrustedOverlay() && other->frameContainsPoint(x, y)) {
             return true;
         }
     }