Ensure forwarding listener target is long-clickable

Also synchronizes with bug fixes in framework version.

Bug: 28550349
Change-Id: I5ba37d75bdb117aa6edbc14b151fc61c4ad96453
diff --git a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java b/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
index 7d53b93..3e4d063 100644
--- a/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
+++ b/v7/appcompat/src/android/support/v7/widget/ForwardingListener.java
@@ -16,13 +16,16 @@
 
 package android.support.v7.widget;
 
+import android.os.Build;
 import android.os.SystemClock;
 import android.support.v4.view.MotionEventCompat;
 import android.support.v7.view.menu.ShowableListMenu;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 
 
 /**
@@ -31,6 +34,7 @@
  * @hide
  */
 public abstract class ForwardingListener implements View.OnTouchListener {
+
     /** Scaled touch slop, used for detecting movement outside bounds. */
     private final float mScaledTouchSlop;
 
@@ -62,12 +66,48 @@
 
     public ForwardingListener(View src) {
         mSrc = src;
+        src.setLongClickable(true);
+
+        if (Build.VERSION.SDK_INT >= 12) {
+            addDetachListenerApi12(src);
+        } else {
+            addDetachListenerBase(src);
+        }
+
         mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
         mTapTimeout = ViewConfiguration.getTapTimeout();
+
         // Use a medium-press timeout. Halfway between tap and long-press.
         mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
     }
 
+    private void addDetachListenerApi12(View src) {
+        src.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+            @Override
+            public void onViewAttachedToWindow(View v) {}
+
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+                onDetachedFromWindow();
+            }
+        });
+    }
+
+    private void addDetachListenerBase(View src) {
+        src.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+            boolean mIsAttached = mSrc.isAttachedToWindow();
+
+            @Override
+            public void onGlobalLayout() {
+                final boolean wasAttached = mIsAttached;
+                mIsAttached = mSrc.isAttachedToWindow();
+                if (wasAttached && !mIsAttached) {
+                    onDetachedFromWindow();
+                }
+            }
+        });
+    }
+
     /**
      * Returns the popup to which this listener is forwarding events.
      * <p>
@@ -103,6 +143,15 @@
         return forwarding || wasForwarding;
     }
 
+    private void onDetachedFromWindow() {
+        mForwarding = false;
+        mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+
+        if (mDisallowIntercept != null) {
+            mSrc.removeCallbacks(mDisallowIntercept);
+        }
+    }
+
     /**
      * Called when forwarding would like to start.
      * <p>