Centralize all system InputEventReceiver monitors.

Implement all system level InputEvent monitors as new
InputEventListeners. Only one InputChannel required and monitoring
can be enabled or disabled by registering with WindowManagerService.

Change-Id: I64714ab858342ed183c62b421098478ffb6637bc
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 6291e62..c735dd7 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -408,11 +408,6 @@
         public int getLidState();
 
         /**
-         * Creates an input channel that will receive all input from the input dispatcher.
-         */
-        public InputChannel monitorInput(String name);
-
-        /**
          * Switch the keyboard layout for the given device.
          * Direction should be +1 or -1 to go to the next or previous keyboard layout.
          */
@@ -425,6 +420,21 @@
          * Return the window manager lock needed to correctly call "Lw" methods.
          */
         public Object getWindowManagerLock();
+
+        /** Register a system listener for touch events */
+        void registerPointerEventListener(PointerEventListener listener);
+
+        /** Unregister a system listener for touch events */
+        void unregisterPointerEventListener(PointerEventListener listener);
+    }
+
+    public interface PointerEventListener {
+        /**
+         * 1. onPointerEvent will be called on the service.UiThread.
+         * 2. motionEvent will be recycled after onPointerEvent returns so if it is needed later a
+         * copy() must be made and the copy must be recycled.
+         **/
+        public void onPointerEvent(MotionEvent motionEvent);
     }
 
     /** Window has been added to the screen. */
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 0da3b56..4930d59 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -296,35 +296,18 @@
     WindowState mFocusedWindow;
     IApplicationToken mFocusedApp;
 
-    private static final class PointerLocationInputEventReceiver extends InputEventReceiver {
-        private final PointerLocationView mView;
-
-        public PointerLocationInputEventReceiver(InputChannel inputChannel, Looper looper,
-                PointerLocationView view) {
-            super(inputChannel, looper);
-            mView = view;
-        }
-
+    private final class PointerLocationPointerEventListener implements PointerEventListener {
         @Override
-        public void onInputEvent(InputEvent event) {
-            boolean handled = false;
-            try {
-                if (event instanceof MotionEvent
-                        && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-                    final MotionEvent motionEvent = (MotionEvent)event;
-                    mView.addPointerEvent(motionEvent);
-                    handled = true;
-                }
-            } finally {
-                finishInputEvent(event, handled);
+        public void onPointerEvent(MotionEvent motionEvent) {
+            if (mPointerLocationView != null) {
+                mPointerLocationView.addPointerEvent(motionEvent);
             }
         }
     }
 
     // Pointer location view state, only modified on the mHandler Looper.
-    PointerLocationInputEventReceiver mPointerLocationInputEventReceiver;
+    PointerLocationPointerEventListener mPointerLocationPointerEventListener;
     PointerLocationView mPointerLocationView;
-    InputChannel mPointerLocationInputChannel;
 
     // The current size of the screen; really; extends into the overscan area of
     // the screen and doesn't account for any system elements like the status bar.
@@ -568,8 +551,7 @@
     private int mStatusHideybar;
     private int mNavigationHideybar;
 
-    private InputChannel mSystemGestureInputChannel;
-    private SystemGestures mSystemGestures;
+    private SystemGesturesPointerEventListener mSystemGestures;
 
     IStatusBarService getStatusBarService() {
         synchronized (mServiceAquireLock) {
@@ -925,10 +907,8 @@
         context.registerReceiver(mMultiuserReceiver, filter);
 
         // monitor for system gestures
-        mSystemGestureInputChannel = mWindowManagerFuncs.monitorInput("SystemGestures");
-        mSystemGestures = new SystemGestures(mSystemGestureInputChannel,
-                mHandler.getLooper(), context,
-                new SystemGestures.Callbacks() {
+        mSystemGestures = new SystemGesturesPointerEventListener(context,
+                new SystemGesturesPointerEventListener.Callbacks() {
                     @Override
                     public void onSwipeFromTop() {
                         if (mStatusBar != null) {
@@ -954,6 +934,7 @@
                         }
                     }
                 });
+        mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
 
         mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
         mLongPressVibePattern = getLongIntArray(mContext.getResources(),
@@ -1212,23 +1193,16 @@
             lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
             wm.addView(mPointerLocationView, lp);
 
-            mPointerLocationInputChannel =
-                    mWindowManagerFuncs.monitorInput("PointerLocationView");
-            mPointerLocationInputEventReceiver =
-                    new PointerLocationInputEventReceiver(mPointerLocationInputChannel,
-                            Looper.myLooper(), mPointerLocationView);
+            mPointerLocationPointerEventListener = new PointerLocationPointerEventListener();
+            mWindowManagerFuncs.registerPointerEventListener(mPointerLocationPointerEventListener);
         }
     }
 
     private void disablePointerLocation() {
-        if (mPointerLocationInputEventReceiver != null) {
-            mPointerLocationInputEventReceiver.dispose();
-            mPointerLocationInputEventReceiver = null;
-        }
-
-        if (mPointerLocationInputChannel != null) {
-            mPointerLocationInputChannel.dispose();
-            mPointerLocationInputChannel = null;
+        if (mPointerLocationPointerEventListener != null) {
+            mWindowManagerFuncs.unregisterPointerEventListener(
+                    mPointerLocationPointerEventListener);
+            mPointerLocationPointerEventListener = null;
         }
 
         if (mPointerLocationView != null) {
diff --git a/policy/src/com/android/internal/policy/impl/SystemGestures.java b/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
similarity index 90%
rename from policy/src/com/android/internal/policy/impl/SystemGestures.java
rename to policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
index c9731a5..6e8c841 100644
--- a/policy/src/com/android/internal/policy/impl/SystemGestures.java
+++ b/policy/src/com/android/internal/policy/impl/SystemGesturesPointerEventListener.java
@@ -17,19 +17,15 @@
 package com.android.internal.policy.impl;
 
 import android.content.Context;
-import android.os.Looper;
 import android.util.Slog;
-import android.view.InputChannel;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
 import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
 
 /*
  * Listens for system-wide input gestures, firing callbacks when detected.
  * @hide
  */
-public class SystemGestures extends InputEventReceiver {
+public class SystemGesturesPointerEventListener implements PointerEventListener {
     private static final String TAG = "SystemGestures";
     private static final boolean DEBUG = false;
     private static final long SWIPE_TIMEOUT_MS = 500;
@@ -55,9 +51,7 @@
     private boolean mSwipeFireable;
     private boolean mDebugFireable;
 
-    public SystemGestures(InputChannel inputChannel, Looper looper,
-            Context context, Callbacks callbacks) {
-        super(inputChannel, looper);
+    public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
         mCallbacks = checkNull("callbacks", callbacks);
         mSwipeStartThreshold = checkNull("context", context).getResources()
                 .getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
@@ -72,14 +66,7 @@
     }
 
     @Override
-    public void onInputEvent(InputEvent event) {
-        if (event instanceof MotionEvent && event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
-            onPointerMotionEvent((MotionEvent) event);
-        }
-        finishInputEvent(event, false /*handled*/);
-    }
-
-    private void onPointerMotionEvent(MotionEvent event) {
+    public void onPointerEvent(MotionEvent event) {
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 mSwipeFireable = true;
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 4a3699c..82e8c7f 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -28,7 +28,6 @@
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
-import android.view.InputChannel;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -101,11 +100,8 @@
     /** Sorted most recent at top, oldest at [0]. */
     ArrayList<TaskStack> mStackHistory = new ArrayList<TaskStack>();
 
-    /** Forward motion events to mTapDetector. */
-    InputChannel mTapInputChannel;
-
     /** Detect user tapping outside of current focused stack bounds .*/
-    StackTapDetector mTapDetector;
+    StackTapPointerEventListener mTapDetector;
 
     /** Detect user tapping outside of current focused stack bounds .*/
     Region mTouchExcludeRegion = new Region();
diff --git a/services/java/com/android/server/wm/PointerEventDispatcher.java b/services/java/com/android/server/wm/PointerEventDispatcher.java
new file mode 100644
index 0000000..6b0e4c9
--- /dev/null
+++ b/services/java/com/android/server/wm/PointerEventDispatcher.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
+
+import com.android.server.UiThread;
+
+import java.util.ArrayList;
+
+public class PointerEventDispatcher extends InputEventReceiver {
+    ArrayList<PointerEventListener> mListeners = new ArrayList<PointerEventListener>();
+    PointerEventListener[] mListenersArray = new PointerEventListener[0];
+
+    public PointerEventDispatcher(InputChannel inputChannel) {
+        super(inputChannel, UiThread.getHandler().getLooper());
+    }
+
+    @Override
+    public void onInputEvent(InputEvent event) {
+        try {
+            if (event instanceof MotionEvent
+                    && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+                final MotionEvent motionEvent = (MotionEvent)event;
+                PointerEventListener[] listeners;
+                synchronized (mListeners) {
+                    if (mListenersArray == null) {
+                        mListenersArray = new PointerEventListener[mListeners.size()];
+                        mListeners.toArray(mListenersArray);
+                    }
+                    listeners = mListenersArray;
+                }
+                for (int i = 0; i < listeners.length; ++i) {
+                    listeners[i].onPointerEvent(motionEvent);
+                }
+            }
+        } finally {
+            finishInputEvent(event, false);
+        }
+    }
+
+    /**
+     * Add the specified listener to the list.
+     * @param listener The listener to add.
+     */
+    public void registerInputEventListener(PointerEventListener listener) {
+        synchronized (mListeners) {
+            if (mListeners.contains(listener)) {
+                throw new IllegalStateException("registerInputEventListener: trying to register" +
+                        listener + " twice.");
+            }
+            mListeners.add(listener);
+            mListenersArray = null;
+        }
+    }
+
+    /**
+     * Remove the specified listener from the list.
+     * @param listener The listener to remove.
+     */
+    public void unregisterInputEventListener(PointerEventListener listener) {
+        synchronized (mListeners) {
+            if (!mListeners.contains(listener)) {
+                throw new IllegalStateException("registerInputEventListener: " + listener +
+                        " not registered.");
+            }
+            mListeners.remove(listener);
+            mListenersArray = null;
+        }
+    }
+}
diff --git a/services/java/com/android/server/wm/StackTapDetector.java b/services/java/com/android/server/wm/StackTapDetector.java
deleted file mode 100644
index 7127fd2..0000000
--- a/services/java/com/android/server/wm/StackTapDetector.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.graphics.Region;
-import android.os.Looper;
-import android.view.DisplayInfo;
-import android.view.InputChannel;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.MotionEvent;
-
-import com.android.server.wm.WindowManagerService.H;
-
-public class StackTapDetector extends InputEventReceiver {
-    private static final int TAP_TIMEOUT_MSEC = 300;
-    private static final float TAP_MOTION_SLOP_INCHES = 0.125f;
-
-    private final int mMotionSlop;
-    private float mDownX;
-    private float mDownY;
-    private int mPointerId;
-    final private Region mTouchExcludeRegion;
-    private final WindowManagerService mService;
-    private final DisplayContent mDisplayContent;
-
-    public StackTapDetector(WindowManagerService service, DisplayContent displayContent,
-            InputChannel inputChannel, Looper looper) {
-        super(inputChannel, looper);
-        mService = service;
-        mDisplayContent = displayContent;
-        mTouchExcludeRegion = displayContent.mTouchExcludeRegion;
-        DisplayInfo info = displayContent.getDisplayInfo();
-        mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES);
-    }
-
-    @Override
-    public void onInputEvent(InputEvent event) {
-        try {
-            if (!(event instanceof MotionEvent)
-                    || !event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
-                return;
-            }
-            final MotionEvent motionEvent = (MotionEvent)event;
-            final int action = motionEvent.getAction();
-            switch (action & MotionEvent.ACTION_MASK) {
-                case MotionEvent.ACTION_DOWN:
-                    mPointerId = motionEvent.getPointerId(0);
-                    mDownX = motionEvent.getX();
-                    mDownY = motionEvent.getY();
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    if (mPointerId >= 0) {
-                        int index = motionEvent.findPointerIndex(mPointerId);
-                        if ((motionEvent.getEventTime() - motionEvent.getDownTime())
-                                > TAP_TIMEOUT_MSEC
-                                || (motionEvent.getX(index) - mDownX) > mMotionSlop
-                                || (motionEvent.getY(index) - mDownY) > mMotionSlop) {
-                            mPointerId = -1;
-                        }
-                    }
-                    break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_POINTER_UP: {
-                    int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                            >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-                    // Extract the index of the pointer that left the touch sensor
-                    if (mPointerId == motionEvent.getPointerId(index)) {
-                        final int x = (int)motionEvent.getX(index);
-                        final int y = (int)motionEvent.getY(index);
-                        synchronized (this) {
-                            if ((motionEvent.getEventTime() - motionEvent.getDownTime())
-                                    < TAP_TIMEOUT_MSEC
-                                    && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop
-                                    && !mTouchExcludeRegion.contains(x, y)) {
-                                mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y,
-                                        mDisplayContent).sendToTarget();
-                            }
-                        }
-                        mPointerId = -1;
-                    }
-                    break;
-                }
-            }
-        } finally {
-            finishInputEvent(event, false /*ignored for monitors*/);
-        }
-    }
-}
diff --git a/services/java/com/android/server/wm/StackTapPointerEventListener.java b/services/java/com/android/server/wm/StackTapPointerEventListener.java
new file mode 100644
index 0000000..19d8ab3
--- /dev/null
+++ b/services/java/com/android/server/wm/StackTapPointerEventListener.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.graphics.Region;
+import android.view.DisplayInfo;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy.PointerEventListener;
+
+import com.android.server.wm.WindowManagerService.H;
+
+public class StackTapPointerEventListener implements PointerEventListener {
+    private static final int TAP_TIMEOUT_MSEC = 300;
+    private static final float TAP_MOTION_SLOP_INCHES = 0.125f;
+
+    private final int mMotionSlop;
+    private float mDownX;
+    private float mDownY;
+    private int mPointerId;
+    final private Region mTouchExcludeRegion;
+    private final WindowManagerService mService;
+    private final DisplayContent mDisplayContent;
+
+    public StackTapPointerEventListener(WindowManagerService service,
+            DisplayContent displayContent) {
+        mService = service;
+        mDisplayContent = displayContent;
+        mTouchExcludeRegion = displayContent.mTouchExcludeRegion;
+        DisplayInfo info = displayContent.getDisplayInfo();
+        mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES);
+    }
+
+    @Override
+    public void onPointerEvent(MotionEvent motionEvent) {
+        final int action = motionEvent.getAction();
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN:
+                mPointerId = motionEvent.getPointerId(0);
+                mDownX = motionEvent.getX();
+                mDownY = motionEvent.getY();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mPointerId >= 0) {
+                    int index = motionEvent.findPointerIndex(mPointerId);
+                    if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC
+                            || (motionEvent.getX(index) - mDownX) > mMotionSlop
+                            || (motionEvent.getY(index) - mDownY) > mMotionSlop) {
+                        mPointerId = -1;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_POINTER_UP: {
+                int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                // Extract the index of the pointer that left the touch sensor
+                if (mPointerId == motionEvent.getPointerId(index)) {
+                    final int x = (int)motionEvent.getX(index);
+                    final int y = (int)motionEvent.getY(index);
+                    if ((motionEvent.getEventTime() - motionEvent.getDownTime())
+                            < TAP_TIMEOUT_MSEC
+                            && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop
+                            && !mTouchExcludeRegion.contains(x, y)) {
+                        mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y,
+                                mDisplayContent).sendToTarget();
+                    }
+                    mPointerId = -1;
+                }
+                break;
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f166c31..079134b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -124,6 +124,7 @@
 import android.view.WindowManagerPolicy;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerPolicy.FakeWindow;
+import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
@@ -281,8 +282,6 @@
     private static final String SYSTEM_SECURE = "ro.secure";
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
-    private static final String TAP_INPUT_CHANNEL_NAME = "StackTapDetector";
-
     private static final int MAX_SCREENSHOT_RETRIES = 3;
 
     final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -594,6 +593,8 @@
     SparseArray<Task> mTaskIdToTask = new SparseArray<Task>();
     SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>();
 
+    private final PointerEventDispatcher mPointerEventDispatcher;
+
     final class DragInputEventReceiver extends InputEventReceiver {
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
@@ -728,6 +729,8 @@
         mDisplaySettings = new DisplaySettings(context);
         mDisplaySettings.readSettingsLocked();
 
+        mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG));
+
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         mDisplayManager.registerDisplayListener(this, null);
         Display[] displays = mDisplayManager.getDisplays();
@@ -5098,6 +5101,16 @@
                 mAnimatorDurationScale };
     }
 
+    @Override
+    public void registerPointerEventListener(PointerEventListener listener) {
+        mPointerEventDispatcher.registerInputEventListener(listener);
+    }
+
+    @Override
+    public void unregisterPointerEventListener(PointerEventListener listener) {
+        mPointerEventDispatcher.unregisterInputEventListener(listener);
+    }
+
     // Called by window manager policy. Not exposed externally.
     @Override
     public int getLidState() {
@@ -5117,12 +5130,6 @@
 
     // Called by window manager policy.  Not exposed externally.
     @Override
-    public InputChannel monitorInput(String inputChannelName) {
-        return mInputManager.monitorInput(inputChannelName);
-    }
-
-    // Called by window manager policy.  Not exposed externally.
-    @Override
     public void switchKeyboardLayout(int deviceId, int direction) {
         mInputManager.switchKeyboardLayout(deviceId, direction);
     }
@@ -10652,10 +10659,8 @@
 
         // TODO: Create an input channel for each display with touch capability.
         if (displayId == Display.DEFAULT_DISPLAY) {
-            InputChannel inputChannel = monitorInput(TAP_INPUT_CHANNEL_NAME);
-            displayContent.mTapInputChannel = inputChannel;
-            displayContent.mTapDetector =
-                    new StackTapDetector(this, displayContent, inputChannel, Looper.myLooper());
+            displayContent.mTapDetector = new StackTapPointerEventListener(this, displayContent);
+            registerPointerEventListener(displayContent.mTapDetector);
         }
 
         return displayContent;
@@ -10838,10 +10843,9 @@
         if (displayContent != null) {
             mDisplayContents.delete(displayId);
 
-            if (displayContent.mTapInputChannel != null) {
-                displayContent.mTapInputChannel.dispose();
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                unregisterPointerEventListener(displayContent.mTapDetector);
             }
-
             WindowList windows = displayContent.getWindowList();
             while (!windows.isEmpty()) {
                 final WindowState win = windows.get(windows.size() - 1);