Introduce an OnDragListener mechanism

If the listener's onDrag(view, event) returns 'false', the view's own
onDragEvent() will be called.  If the listener returns 'true', it
consumes the event (and declares that it will handle the rest of the
drag event sequence, in the case of DRAG_STARTED actions).

Change-Id: I01aff0e4f59f71e55f5eea1049905c80714f0607
diff --git a/api/current.xml b/api/current.xml
index 095ead5..baa5631e 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -203876,6 +203876,19 @@
 <parameter name="l" type="android.view.View.OnCreateContextMenuListener">
 </parameter>
 </method>
+<method name="setOnDragListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="l" type="android.view.View.OnDragListener">
+</parameter>
+</method>
 <method name="setOnFocusChangeListener"
  return="void"
  abstract="false"
@@ -205285,6 +205298,29 @@
 </parameter>
 </method>
 </interface>
+<interface name="View.OnDragListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onDrag"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.view.View">
+</parameter>
+<parameter name="event" type="android.view.DragEvent">
+</parameter>
+</method>
+</interface>
 <interface name="View.OnFocusChangeListener"
  abstract="true"
  static="true"
@@ -244067,7 +244103,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2b63eff..baa749a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1943,6 +1943,8 @@
 
     private OnTouchListener mOnTouchListener;
 
+    private OnDragListener mOnDragListener;
+
     /**
      * The application environment this view lives in.
      * This field should be made private, so it is hidden from the SDK.
@@ -2739,6 +2741,14 @@
     }
 
     /**
+     * Register a callback to be invoked when a drag event is sent to this view.
+     * @param l The drag listener to attach to this view
+     */
+    public void setOnDragListener(OnDragListener l) {
+        mOnDragListener = l;
+    }
+
+    /**
      * Give this view focus. This will cause {@link #onFocusChanged} to be called.
      *
      * Note: this does not check whether this {@link View} should get focus, it just
@@ -9994,10 +10004,13 @@
 
     /**
      * Views typically don't need to override dispatchDragEvent(); it just calls
-     * onDragEvent(what, event) and passes the result up appropriately.
-     *
+     * onDragEvent(event) and passes the result up appropriately.
      */
     public boolean dispatchDragEvent(DragEvent event) {
+        if (mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
+                && mOnDragListener.onDrag(this, event)) {
+            return true;
+        }
         return onDragEvent(event);
     }
 
@@ -10288,6 +10301,26 @@
     }
 
     /**
+     * Interface definition for a callback to be invoked when a drag is being dispatched
+     * to this view.  The callback will be invoked before the hosting view's own
+     * onDrag(event) method.  If the listener wants to fall back to the hosting view's
+     * onDrag(event) behavior, it should return 'false' from this callback.
+     */
+    public interface OnDragListener {
+        /**
+         * Called when a drag event is dispatched to a view. This allows listeners
+         * to get a chance to override base View behavior.
+         *
+         * @param v The view the drag has been dispatched to.
+         * @param event The DragEvent object containing full information
+         *        about the event.
+         * @return true if the listener consumed the DragEvent, false in order to fall
+         *         back to the view's default handling.
+         */
+        boolean onDrag(View v, DragEvent event);
+    }
+
+    /**
      * Interface definition for a callback to be invoked when the focus state of
      * a view changed.
      */
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4eea2d2..69f34b6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -954,7 +954,8 @@
 
         // If none of our children could handle the event, try here
         if (!retval) {
-            retval = onDragEvent(event);
+            // Call up to the View implementation that dispatches to installed listeners
+            retval = super.dispatchDragEvent(event);
         }
         return retval;
     }