Fixed that touches where incorrectly consumed when fullscreen

The fake window that was added when View.SYSTEM_UI_FULL_SCREEN was
set consumed all touches, even those going to the SystemUI and not
just those of windows below. The input consumer is now correctly
positioned in the window order to only capture the right touches.
Clicks to the volume panel and the heads up now correctly go to the
right place instead of just unhiding the SystemUI bars.

Bug: 21089476
Change-Id: Ib53dfc0b33b70084ca607d0f044db30b6e6c91d6
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a4e9c68..9bb5e40 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -51,7 +51,6 @@
 import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.media.session.MediaSessionLegacyHelper;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.FactoryTest;
@@ -97,7 +96,6 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.ViewRootImpl;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -458,7 +456,7 @@
     // menu needs to be displayed.
     boolean mLastFocusNeedsMenu = false;
 
-    FakeWindow mHideNavFakeWindow = null;
+    InputConsumer mInputConsumer = null;
 
     static final Rect mTmpParentFrame = new Rect();
     static final Rect mTmpDisplayFrame = new Rect();
@@ -1817,7 +1815,7 @@
             case TYPE_APPLICATION_STARTING:
             case TYPE_BOOT_PROGRESS:
             case TYPE_DISPLAY_OVERLAY:
-            case TYPE_HIDDEN_NAV_CONSUMER:
+            case TYPE_INPUT_CONSUMER:
             case TYPE_KEYGUARD_SCRIM:
             case TYPE_KEYGUARD_DIALOG:
             case TYPE_MAGNIFICATION_OVERLAY:
@@ -1942,75 +1940,75 @@
         case TYPE_VOICE_INTERACTION:
             // voice interaction layer is almost immediately above apps.
             return 5;
-        case TYPE_SYSTEM_DIALOG:
+        case TYPE_INPUT_CONSUMER:
             return 6;
+        case TYPE_SYSTEM_DIALOG:
+            return 7;
         case TYPE_TOAST:
             // toasts and the plugged-in battery thing
-            return 7;
+            return 8;
         case TYPE_PRIORITY_PHONE:
             // SIM errors and unlock.  Not sure if this really should be in a high layer.
-            return 8;
+            return 9;
         case TYPE_DREAM:
             // used for Dreams (screensavers with TYPE_DREAM windows)
-            return 9;
+            return 10;
         case TYPE_SYSTEM_ALERT:
             // like the ANR / app crashed dialogs
-            return 10;
+            return 11;
         case TYPE_INPUT_METHOD:
             // on-screen keyboards and other such input method user interfaces go here.
-            return 11;
+            return 12;
         case TYPE_INPUT_METHOD_DIALOG:
             // on-screen keyboards and other such input method user interfaces go here.
-            return 12;
+            return 13;
         case TYPE_KEYGUARD_SCRIM:
             // the safety window that shows behind keyguard while keyguard is starting
-            return 13;
-        case TYPE_STATUS_BAR_SUB_PANEL:
             return 14;
-        case TYPE_STATUS_BAR:
+        case TYPE_STATUS_BAR_SUB_PANEL:
             return 15;
-        case TYPE_STATUS_BAR_PANEL:
+        case TYPE_STATUS_BAR:
             return 16;
-        case TYPE_KEYGUARD_DIALOG:
+        case TYPE_STATUS_BAR_PANEL:
             return 17;
+        case TYPE_KEYGUARD_DIALOG:
+            return 18;
         case TYPE_VOLUME_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 18;
+            return 19;
         case TYPE_SYSTEM_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 19;
+            return 20;
         case TYPE_NAVIGATION_BAR:
             // the navigation bar, if available, shows atop most things
-            return 20;
+            return 21;
         case TYPE_NAVIGATION_BAR_PANEL:
             // some panels (e.g. search) need to show on top of the navigation bar
-            return 21;
+            return 22;
         case TYPE_SYSTEM_ERROR:
             // system-level error dialogs
-            return 22;
+            return 23;
         case TYPE_MAGNIFICATION_OVERLAY:
             // used to highlight the magnified portion of a display
-            return 23;
+            return 24;
         case TYPE_DISPLAY_OVERLAY:
             // used to simulate secondary display devices
-            return 24;
+            return 25;
         case TYPE_DRAG:
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
-            return 25;
+            return 26;
         case TYPE_ACCESSIBILITY_OVERLAY:
             // overlay put by accessibility services to intercept user interaction
-            return 26;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 27;
-        case TYPE_BOOT_PROGRESS:
+        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 28;
+        case TYPE_BOOT_PROGRESS:
+            return 29;
         case TYPE_POINTER:
             // the (mouse) pointer layer
-            return 29;
-        case TYPE_HIDDEN_NAV_CONSUMER:
             return 30;
         }
         Log.e(TAG, "Unknown window type: " + type);
@@ -3385,15 +3383,13 @@
             // detect when the user presses anywhere to bring back the nav
             // bar and ensure the application doesn't see the event.
             if (navVisible || navAllowedHidden) {
-                if (mHideNavFakeWindow != null) {
-                    mHideNavFakeWindow.dismiss();
-                    mHideNavFakeWindow = null;
+                if (mInputConsumer != null) {
+                    mInputConsumer.dismiss();
+                    mInputConsumer = null;
                 }
-            } else if (mHideNavFakeWindow == null) {
-                mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
-                        mHandler.getLooper(), mHideNavInputEventReceiverFactory,
-                        "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER, 0,
-                        0, false, false, true);
+            } else if (mInputConsumer == null) {
+                mInputConsumer = mWindowManagerFuncs.addInputConsumer(mHandler.getLooper(),
+                        mHideNavInputEventReceiverFactory);
             }
 
             // For purposes of positioning and showing the nav bar, if we have
@@ -6311,7 +6307,8 @@
         vis = mNavigationBarController.applyTranslucentFlagLw(transWin, vis, oldVis);
 
         // prevent status bar interaction from clearing certain flags
-        boolean statusBarHasFocus = win.getAttrs().type == TYPE_STATUS_BAR;
+        int type = win.getAttrs().type;
+        boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
         if (statusBarHasFocus && !isStatusBarKeyguard()) {
             int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
@@ -6323,6 +6320,11 @@
             }
             vis = (vis & ~flags) | (oldVis & flags);
         }
+        if (windowTypeToLayerLw(type) > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) {
+            // We can't get into fullscreen from this window otherwise the consumer would not get
+            // the input events.
+            vis = (vis & ~View.SYSTEM_UI_FLAG_FULLSCREEN);
+        }
 
         if (!areTranslucentBarsAllowed() && transWin != mStatusBar) {
             vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 482ae24..66ae9ef 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1248,7 +1248,7 @@
                     && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
                     && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
                     && windowType != WindowManager.LayoutParams.TYPE_DRAG
-                    && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER
+                    && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
                     && windowType != WindowManager.LayoutParams.TYPE_POINTER
                     && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
                     && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
diff --git a/services/core/java/com/android/server/wm/FakeWindowImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
similarity index 77%
rename from services/core/java/com/android/server/wm/FakeWindowImpl.java
rename to services/core/java/com/android/server/wm/InputConsumerImpl.java
index 1136ced..0581a16 100644
--- a/services/core/java/com/android/server/wm/FakeWindowImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,17 +16,18 @@
 
 package com.android.server.wm;
 
-import com.android.server.input.InputApplicationHandle;
-import com.android.server.input.InputWindowHandle;
-
 import android.os.Looper;
 import android.os.Process;
 import android.view.Display;
 import android.view.InputChannel;
 import android.view.InputEventReceiver;
+import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 
-public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow {
+import com.android.server.input.InputApplicationHandle;
+import com.android.server.input.InputWindowHandle;
+
+public final class InputConsumerImpl implements WindowManagerPolicy.InputConsumer {
     final WindowManagerService mService;
     final InputChannel mServerChannel, mClientChannel;
     final InputApplicationHandle mApplicationHandle;
@@ -34,12 +35,9 @@
     final InputEventReceiver mInputEventReceiver;
     final int mWindowLayer;
 
-    boolean mTouchFullscreen;
-
-    public FakeWindowImpl(WindowManagerService service,
-            Looper looper, InputEventReceiver.Factory inputEventReceiverFactory,
-            String name, int windowType, int layoutParamsFlags,
-            boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) {
+    public InputConsumerImpl(WindowManagerService service, Looper looper,
+            InputEventReceiver.Factory inputEventReceiverFactory) {
+        String name = "input consumer";
         mService = service;
 
         InputChannel[] channels = InputChannel.openInputChannelPair(name);
@@ -58,31 +56,25 @@
         mWindowHandle = new InputWindowHandle(mApplicationHandle, null, Display.DEFAULT_DISPLAY);
         mWindowHandle.name = name;
         mWindowHandle.inputChannel = mServerChannel;
-        mWindowLayer = getLayerLw(windowType);
+        mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+        mWindowLayer = getLayerLw(mWindowHandle.layoutParamsType);
         mWindowHandle.layer = mWindowLayer;
-        mWindowHandle.layoutParamsFlags = layoutParamsFlags;
-        mWindowHandle.layoutParamsType = windowType;
+        mWindowHandle.layoutParamsFlags = 0;
         mWindowHandle.dispatchingTimeoutNanos =
                 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
         mWindowHandle.visible = true;
-        mWindowHandle.canReceiveKeys = canReceiveKeys;
-        mWindowHandle.hasFocus = hasFocus;
+        mWindowHandle.canReceiveKeys = false;
+        mWindowHandle.hasFocus = false;
         mWindowHandle.hasWallpaper = false;
         mWindowHandle.paused = false;
         mWindowHandle.ownerPid = Process.myPid();
         mWindowHandle.ownerUid = Process.myUid();
         mWindowHandle.inputFeatures = 0;
         mWindowHandle.scaleFactor = 1.0f;
-
-        mTouchFullscreen = touchFullscreen;
     }
 
     void layout(int dw, int dh) {
-        if (mTouchFullscreen) {
-            mWindowHandle.touchableRegion.set(0, 0, dw, dh);
-        } else {
-            mWindowHandle.touchableRegion.setEmpty();
-        }
+        mWindowHandle.touchableRegion.set(0, 0, dw, dh);
         mWindowHandle.frameLeft = 0;
         mWindowHandle.frameTop = 0;
         mWindowHandle.frameRight = dw;
@@ -92,7 +84,7 @@
     @Override
     public void dismiss() {
         synchronized (mService.mWindowMap) {
-            if (mService.removeFakeWindowLocked(this)) {
+            if (mService.removeInputConsumer()) {
                 mInputEventReceiver.dispose();
                 mService.mInputManager.unregisterInputChannel(mServerChannel);
                 mClientChannel.dispose();
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index c24fcb3..ae442e5 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,10 +16,6 @@
 
 package com.android.server.wm;
 
-import com.android.server.input.InputManagerService;
-import com.android.server.input.InputApplicationHandle;
-import com.android.server.input.InputWindowHandle;
-
 import android.app.ActivityManagerNative;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -30,17 +26,21 @@
 import android.view.KeyEvent;
 import android.view.WindowManager;
 
+import com.android.server.input.InputApplicationHandle;
+import com.android.server.input.InputManagerService;
+import com.android.server.input.InputWindowHandle;
+
 import java.util.Arrays;
 
 final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
     private final WindowManagerService mService;
-    
+
     // Current window with input focus for keys and other non-touch events.  May be null.
     private WindowState mInputFocus;
-    
+
     // When true, prevents input dispatch from proceeding until set to false again.
     private boolean mInputDispatchFrozen;
-    
+
     // When true, input dispatch proceeds normally.  Otherwise all events are dropped.
     // Initially false, so that input does not get dispatched until boot is finished at
     // which point the ActivityManager will enable dispatching.
@@ -256,10 +256,7 @@
             }
         }
 
-        final int NFW = mService.mFakeWindows.size();
-        for (int i = 0; i < NFW; i++) {
-            addInputWindowHandleLw(mService.mFakeWindows.get(i).mWindowHandle);
-        }
+        boolean addInputConsumerHandle = mService.mInputConsumer != null;
 
         // Add all windows on the default display.
         final int numDisplays = mService.mDisplayContents.size();
@@ -273,6 +270,11 @@
                     // Skip this window because it cannot possibly receive input.
                     continue;
                 }
+                if (addInputConsumerHandle
+                        && inputWindowHandle.layer <= mService.mInputConsumer.mWindowHandle.layer) {
+                    addInputWindowHandleLw(mService.mInputConsumer.mWindowHandle);
+                    addInputConsumerHandle = false;
+                }
 
                 final int flags = child.mAttrs.flags;
                 final int privateFlags = child.mAttrs.privateFlags;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d956d76..cebb909 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -108,7 +108,6 @@
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerInternal;
 import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.FakeWindow;
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -382,10 +381,10 @@
     final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>();
 
     /**
-     * Fake windows added to the window manager.  Note: ordered from top to
-     * bottom, opposite of mWindows.
+     * The input consumer added to the window manager which consumes input events to windows below
+     * it.
      */
-    final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<>();
+    InputConsumerImpl mInputConsumer;
 
     /**
      * Windows that are being resized.  Used so we can tell the client about
@@ -8966,9 +8965,8 @@
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
 
-        final int NFW = mFakeWindows.size();
-        for (int i=0; i<NFW; i++) {
-            mFakeWindows.get(i).layout(dw, dh);
+        if (mInputConsumer != null) {
+            mInputConsumer.layout(dw, dh);
         }
 
         final int N = windows.size();
@@ -10995,28 +10993,19 @@
     }
 
     @Override
-    public FakeWindow addFakeWindow(Looper looper,
-            InputEventReceiver.Factory inputEventReceiverFactory,
-            String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags,
-            boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) {
+    public InputConsumerImpl addInputConsumer(Looper looper,
+            InputEventReceiver.Factory inputEventReceiverFactory) {
         synchronized (mWindowMap) {
-            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
-                    name, windowType, layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
-            int i=0;
-            while (i<mFakeWindows.size()) {
-                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
-                    break;
-                }
-            }
-            mFakeWindows.add(i, fw);
+            mInputConsumer = new InputConsumerImpl(this, looper, inputEventReceiverFactory);
             mInputMonitor.updateInputWindowsLw(true);
-            return fw;
+            return mInputConsumer;
         }
     }
 
-    boolean removeFakeWindowLocked(FakeWindow window) {
+    boolean removeInputConsumer() {
         synchronized (mWindowMap) {
-            if (mFakeWindows.remove(window)) {
+            if (mInputConsumer != null) {
+                mInputConsumer = null;
                 mInputMonitor.updateInputWindowsLw(true);
                 return true;
             }