Only provide the resolved activity info to the global intercept window

- Previously we were adding the activity info to the ClipData, but
  that data is provided to non-intercept windows when the drop happens
  and can be retrieved using reflection. The intention was only to
  provide this activity info to the shell global intercept window
  for invoking split.

  Instead of baking the info into the ClipData, we pass the resolved
  info along side the data and only construct a ClipData with the
  additional info for the intercept window.

Fixes: 191057499
Test: atest DragDropControllerTests
Change-Id: I2ccc9f1f666ff2a388f22b6e6a7b5eea3102964c
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 54b39bd..0bc459a 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -179,6 +179,10 @@
 
     final ArrayList<Item> mItems;
 
+    // This is false by default unless the ClipData is obtained via
+    // {@link #copyForTransferWithActivityInfo}.
+    private boolean mParcelItemActivityInfos;
+
     /**
      * Description of a single item in a ClipData.
      *
@@ -204,9 +208,11 @@
         final Intent mIntent;
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         Uri mUri;
-        // Additional activity info resolved by the system
-        ActivityInfo mActivityInfo;
         private TextLinks mTextLinks;
+        // Additional activity info resolved by the system. This is only parceled with the ClipData
+        // if the data is obtained from {@link #copyForTransferWithActivityInfo}
+        private ActivityInfo mActivityInfo;
+
 
         /** @hide */
         public Item(Item other) {
@@ -214,6 +220,8 @@
             mHtmlText = other.mHtmlText;
             mIntent = other.mIntent;
             mUri = other.mUri;
+            mActivityInfo = other.mActivityInfo;
+            mTextLinks = other.mTextLinks;
         }
 
         /**
@@ -817,6 +825,24 @@
     }
 
     /**
+     * Returns a copy of the ClipData which will parcel the Item's activity infos.
+     * @hide
+     */
+    public ClipData copyForTransferWithActivityInfo() {
+        ClipData copy = new ClipData(this);
+        copy.mParcelItemActivityInfos = true;
+        return copy;
+    }
+
+    /**
+     * Returns whether this clip data will parcel the Item's activity infos.
+     * @hide
+     */
+    public boolean willParcelWithActivityInfo() {
+        return mParcelItemActivityInfos;
+    }
+
+    /**
      * Create a new ClipData holding data of the type
      * {@link ClipDescription#MIMETYPE_TEXT_PLAIN}.
      *
@@ -1208,7 +1234,7 @@
             dest.writeString8(item.mHtmlText);
             dest.writeTypedObject(item.mIntent, flags);
             dest.writeTypedObject(item.mUri, flags);
-            dest.writeTypedObject(item.mActivityInfo, flags);
+            dest.writeTypedObject(mParcelItemActivityInfos ? item.mActivityInfo : null, flags);
             dest.writeTypedObject(item.mTextLinks, flags);
         }
     }
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index c674cb85..18ea738b 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -316,7 +316,7 @@
         final int myPid = Process.myPid();
         final IBinder clientToken = touchedWin.mClient.asBinder();
         final DragEvent event = obtainDragEvent(DragEvent.ACTION_DROP, x, y,
-                true /* includeData */, targetInterceptsGlobalDrag(touchedWin),
+                mData, targetInterceptsGlobalDrag(touchedWin),
                 dragAndDropPermissions);
         try {
             touchedWin.mClient.dispatchDragEvent(event);
@@ -462,8 +462,10 @@
             boolean containsAppExtras) {
         final boolean interceptsGlobalDrag = targetInterceptsGlobalDrag(newWin);
         if (mDragInProgress && isValidDropTarget(newWin, containsAppExtras, interceptsGlobalDrag)) {
+            // Only allow the extras to be dispatched to a global-intercepting drag target
+            ClipData data = interceptsGlobalDrag ? mData.copyForTransferWithActivityInfo() : null;
             DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED, touchX, touchY,
-                    interceptsGlobalDrag, false /* includeDragSurface */,
+                    data, false /* includeDragSurface */,
                     null /* dragAndDropPermission */);
             try {
                 newWin.mClient.dispatchDragEvent(event);
@@ -614,11 +616,11 @@
         return mDragInProgress;
     }
 
-    private DragEvent obtainDragEvent(int action, float x, float y, boolean includeData,
+    private DragEvent obtainDragEvent(int action, float x, float y, ClipData data,
             boolean includeDragSurface, IDragAndDropPermissions dragAndDropPermissions) {
         return DragEvent.obtain(action, x, y, mThumbOffsetX, mThumbOffsetY,
-                null  /* localState */, mDataDescription,
-                includeData ? mData : null, includeDragSurface ? mSurfaceControl : null,
+                null  /* localState */, mDataDescription, data,
+                includeDragSurface ? mSurfaceControl : null,
                 dragAndDropPermissions, false /* result */);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 8981ab1..223dc31 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -22,6 +22,7 @@
 import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.view.DragEvent.ACTION_DRAG_STARTED;
+import static android.view.DragEvent.ACTION_DROP;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
@@ -31,7 +32,9 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.eq;
@@ -267,12 +270,32 @@
                     assertTrue(globalInterceptWindowDragEvents.get(0).getAction()
                             == ACTION_DRAG_STARTED);
 
+                    // Verify that only the global intercept window receives the clip data with the
+                    // resolved activity info for the drag
+                    assertNull(localWindowDragEvents.get(0).getClipData());
+                    assertTrue(globalInterceptWindowDragEvents.get(0).getClipData()
+                            .willParcelWithActivityInfo());
+
                     mTarget.reportDropWindow(globalInterceptWindow.mInputChannelToken, 0, 0);
                     mTarget.handleMotionEvent(false, 0, 0);
                     mToken = globalInterceptWindow.mClient.asBinder();
+
+                    // Verify the drop event is only sent for the global intercept window
+                    assertTrue(nonLocalWindowDragEvents.isEmpty());
+                    assertTrue(last(localWindowDragEvents).getAction() != ACTION_DROP);
+                    assertTrue(last(globalInterceptWindowDragEvents).getAction() == ACTION_DROP);
+
+                    // Verify that item extras were not sent with the drop event
+                    assertNull(last(localWindowDragEvents).getClipData());
+                    assertFalse(last(globalInterceptWindowDragEvents).getClipData()
+                            .willParcelWithActivityInfo());
                 });
     }
 
+    private DragEvent last(ArrayList<DragEvent> list) {
+        return list.get(list.size() - 1);
+    }
+
     @Test
     public void testValidateAppActivityArguments() {
         final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {