Remove DragDropController#prepareDrag()

The prepareDrag() call is used by apps to ask the system server to
create a surface for drag shadow. Now the app creates a surface by
itself, thus we can reduce the method.

Bug: 70818582
Test: com.android.server.wm.DragDropControllerTests,
      android.server.wm.CrossAppDragAndDropTests,
      manually check the drag and drop behavior on test app.
Change-Id: Iae4acbff4f9ad68faa6324beb32bf9a28dcd67be
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index a7112ba..f544c18 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -151,18 +151,25 @@
     boolean performHapticFeedback(IWindow window, int effectId, boolean always);
 
     /**
-     * Allocate the drag's thumbnail surface.  Also assigns a token that identifies
-     * the drag to the OS and passes that as the return value.  A return value of
-     * null indicates failure.
-     */
-    IBinder prepareDrag(IWindow window, int flags, int thumbnailWidth, int thumbnailHeight);
-
-    /**
      * Initiate the drag operation itself
+     *
+     * @param window Window which initiates drag operation.
+     * @param flags See {@code View#startDragAndDrop}
+     * @param surface Surface containing drag shadow image
+     * @param touchSource See {@code InputDevice#getSource()}
+     * @param touchX TODO (b/72072998): Fix the issue that the system server misuse the arguments as
+     *         initial touch point while the framework passes drag shadow size.
+     * @param touchY TODO (b/72072998): Fix the issue that the system server misuse the arguments as
+     *         initial touch point while the framework passes drag shadow size.
+     * @param thumbCenterX X coordinate for the position within the shadow image that should be
+     *         underneath the touch point during the drag and drop operation.
+     * @param thumbCenterY Y coordinate for the position within the shadow image that should be
+     *         underneath the touch point during the drag and drop operation.
+     * @param data Data transferred by drag and drop
+     * @return Token of drag operation which will be passed to cancelDragAndDrop.
      */
-    boolean performDrag(IWindow window, IBinder dragToken, in SurfaceControl surface,
-            int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
-            in ClipData data);
+    IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource,
+            float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);
 
     /**
      * Report the result of a drop action targeted to the given window.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 34ad91c7..c18be40 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -23496,8 +23496,6 @@
             data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
         }
 
-        boolean okay = false;
-
         Point shadowSize = new Point();
         Point shadowTouchPoint = new Point();
         shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
@@ -23515,50 +23513,50 @@
             mAttachInfo.mDragSurface.release();
         }
         mAttachInfo.mDragSurface = new Surface();
+        mAttachInfo.mDragToken = null;
 
         final ViewRootImpl root = mAttachInfo.mViewRootImpl;
         final SurfaceSession session = new SurfaceSession(root.mSurface);
+        final SurfaceControl surface = new SurfaceControl.Builder(session)
+                .setName("drag surface")
+                .setSize(shadowSize.x, shadowSize.y)
+                .setFormat(PixelFormat.TRANSLUCENT)
+                .build();
         try {
-            mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow,
-                    flags, shadowSize.x, shadowSize.y);
-            if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token="
-                    + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface);
-            if (mAttachInfo.mDragToken != null) {
-                final SurfaceControl surface = new SurfaceControl.Builder(session)
-                        .setName("drag surface")
-                        .setSize(shadowSize.x, shadowSize.y)
-                        .setFormat(PixelFormat.TRANSLUCENT)
-                        .build();
-                mAttachInfo.mDragSurface.copyFrom(surface);
-                final Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
-                try {
-                    canvas.drawColor(0, PorterDuff.Mode.CLEAR);
-                    shadowBuilder.onDrawShadow(canvas);
-                } finally {
-                    mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas);
-                }
-
-                // Cache the local state object for delivery with DragEvents
-                root.setLocalDragState(myLocalState);
-
-                // repurpose 'shadowSize' for the last touch point
-                root.getLastTouchPoint(shadowSize);
-
-                okay = mAttachInfo.mSession.performDrag(
-                        mAttachInfo.mWindow, mAttachInfo.mDragToken, surface,
-                        root.getLastTouchSource(), shadowSize.x, shadowSize.y, shadowTouchPoint.x,
-                        shadowTouchPoint.y, data);
-                if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
+            mAttachInfo.mDragSurface.copyFrom(surface);
+            final Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
+            try {
+                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+                shadowBuilder.onDrawShadow(canvas);
+            } finally {
+                mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas);
             }
+
+            // Cache the local state object for delivery with DragEvents
+            root.setLocalDragState(myLocalState);
+
+            // repurpose 'shadowSize' for the last touch point
+            root.getLastTouchPoint(shadowSize);
+
+            mAttachInfo.mDragToken = mAttachInfo.mSession.performDrag(
+                    mAttachInfo.mWindow, flags, surface, root.getLastTouchSource(),
+                    shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data);
+            if (ViewDebug.DEBUG_DRAG) {
+                Log.d(VIEW_LOG_TAG, "performDrag returned " + mAttachInfo.mDragToken);
+            }
+
+            return mAttachInfo.mDragToken != null;
         } catch (Exception e) {
             Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
-            mAttachInfo.mDragSurface.destroy();
-            mAttachInfo.mDragSurface = null;
+            return false;
         } finally {
+            if (mAttachInfo.mDragToken == null) {
+                mAttachInfo.mDragSurface.destroy();
+                mAttachInfo.mDragSurface = null;
+                root.setLocalDragState(null);
+            }
             session.kill();
         }
-
-        return okay;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index bf97bd2..d55a649 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -48,10 +48,9 @@
     private static final long DRAG_TIMEOUT_MS = 5000;
 
     // Messages for Handler.
-    private static final int MSG_DRAG_START_TIMEOUT = 0;
-    static final int MSG_DRAG_END_TIMEOUT = 1;
-    static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 2;
-    static final int MSG_ANIMATION_END = 3;
+    static final int MSG_DRAG_END_TIMEOUT = 0;
+    static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 1;
+    static final int MSG_ANIMATION_END = 2;
 
     /**
      * Drag state per operation.
@@ -93,72 +92,35 @@
         mDragState.sendDragStartedIfNeededLocked(window);
     }
 
-    IBinder prepareDrag(SurfaceSession session, int callerPid,
-            int callerUid, IWindow window, int flags, int width, int height) {
+    IBinder performDrag(SurfaceSession session, int callerPid, int callerUid, IWindow window,
+            int flags, SurfaceControl surface, int touchSource, float touchX, float touchY,
+            float thumbCenterX, float thumbCenterY, ClipData data) {
         if (DEBUG_DRAG) {
-            Slog.d(TAG_WM, "prepare drag surface: w=" + width + " h=" + height
-                    + " flags=" + Integer.toHexString(flags) + " win=" + window
-                    + " asbinder=" + window.asBinder());
+            Slog.d(TAG_WM, "perform drag: win=" + window + " surface=" + surface + " flags=" +
+                            Integer.toHexString(flags) + " data=" + data);
         }
 
-        if (width <= 0 || height <= 0) {
-            Slog.w(TAG_WM, "width and height of drag shadow must be positive");
-            return null;
-        }
-
-        synchronized (mService.mWindowMap) {
-            if (dragDropActiveLocked()) {
-                Slog.w(TAG_WM, "Drag already in progress");
-                return null;
-            }
-
-            // TODO(multi-display): support other displays
-            float alpha = 1;
-            if ((flags & View.DRAG_FLAG_OPAQUE) == 0) {
-                alpha = DRAG_SHADOW_ALPHA_TRANSPARENT;
-            }
-            final IBinder winBinder = window.asBinder();
-            IBinder token = new Binder();
-            mDragState = new DragState(mService, this, token, /* surface */ null, flags, winBinder);
-            mDragState.mPid = callerPid;
-            mDragState.mUid = callerUid;
-            mDragState.mOriginalAlpha = alpha;
-            token = mDragState.mToken = new Binder();
-
-            // 5 second timeout for this window to actually begin the drag
-            sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
-            return token;
-        }
-    }
-
-    boolean performDrag(SurfaceSession session, IWindow window, IBinder dragToken,
-            SurfaceControl surface, int touchSource, float touchX, float touchY, float thumbCenterX,
-            float thumbCenterY, ClipData data) {
-        if (DEBUG_DRAG) {
-            Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data);
-        }
-
+        final IBinder dragToken = new Binder();
         final boolean callbackResult = mCallback.get().prePerformDrag(window, dragToken,
                 touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
         try {
             synchronized (mService.mWindowMap) {
-                mHandler.removeMessages(MSG_DRAG_START_TIMEOUT, window.asBinder());
                 try {
                     if (!callbackResult) {
-                        return false;
+                        Slog.w(TAG_WM, "IDragDropCallback rejects the performDrag request");
+                        return null;
                     }
 
-                    Preconditions.checkState(
-                            mDragState != null, "performDrag() without prepareDrag()");
-                    Preconditions.checkState(
-                            mDragState.mToken == dragToken,
-                            "performDrag() does not match prepareDrag()");
+                    if (dragDropActiveLocked()) {
+                        Slog.w(TAG_WM, "Drag already in progress");
+                        return null;
+                    }
 
                     final WindowState callingWin = mService.windowForClientLocked(
                             null, window, false);
                     if (callingWin == null) {
                         Slog.w(TAG_WM, "Bad requesting window " + window);
-                        return false;  // !!! TODO: throw here?
+                        return null;  // !!! TODO: throw here?
                     }
 
                     // !!! TODO: if input is not still focused on the initiating window, fail
@@ -171,22 +133,33 @@
                     // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
                     // the actual drag event dispatch stuff in the dragstate
 
+                    // !!! TODO(multi-display): support other displays
+
                     final DisplayContent displayContent = callingWin.getDisplayContent();
                     if (displayContent == null) {
                         Slog.w(TAG_WM, "display content is null");
-                        return false;
+                        return null;
                     }
 
+                    final float alpha = (flags & View.DRAG_FLAG_OPAQUE) == 0 ?
+                            DRAG_SHADOW_ALPHA_TRANSPARENT : 1;
+                    final IBinder winBinder = window.asBinder();
+                    IBinder token = new Binder();
+                    mDragState = new DragState(mService, this, token, surface, flags, winBinder);
+                    surface = null;
+                    mDragState.mPid = callerPid;
+                    mDragState.mUid = callerUid;
+                    mDragState.mOriginalAlpha = alpha;
+                    mDragState.mToken = dragToken;
+
                     final Display display = displayContent.getDisplay();
                     mDragState.register(display);
                     if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
                             mDragState.getInputChannel())) {
                         Slog.e(TAG_WM, "Unable to transfer touch focus");
-                        return false;
+                        return null;
                     }
 
-                    mDragState.mSurfaceControl = surface;
-                    surface = null;
                     mDragState.mDisplayContent = displayContent;
                     mDragState.mData = data;
                     mDragState.broadcastDragStartedLocked(touchX, touchY);
@@ -222,7 +195,7 @@
                     }
                 }
             }
-            return true;    // success!
+            return dragToken;    // success!
         } finally {
             mCallback.get().postPerformDrag();
         }
@@ -373,21 +346,6 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_DRAG_START_TIMEOUT: {
-                    IBinder win = (IBinder) msg.obj;
-                    if (DEBUG_DRAG) {
-                        Slog.w(TAG_WM, "Timeout starting drag by win " + win);
-                    }
-
-                    synchronized (mService.mWindowMap) {
-                        // !!! TODO: ANR the app that has failed to start the drag in time
-                        if (mDragState != null) {
-                            mDragState.closeLocked();
-                        }
-                    }
-                    break;
-                }
-
                 case MSG_DRAG_END_TIMEOUT: {
                     final IBinder win = (IBinder) msg.obj;
                     if (DEBUG_DRAG) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 9280620..b8c7d61 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -309,28 +309,22 @@
     }
 
     /* Drag/drop */
+
     @Override
-    public IBinder prepareDrag(IWindow window, int flags, int width, int height) {
+    public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
+            float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
         final int callerPid = Binder.getCallingPid();
         final int callerUid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         try {
-            return mDragDropController.prepareDrag(mSurfaceSession, callerPid, callerUid, window,
-                    flags, width, height);
+            return mDragDropController.performDrag(mSurfaceSession, callerPid, callerUid, window,
+                    flags, surface, touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override
-    public boolean performDrag(IWindow window, IBinder dragToken, SurfaceControl surface,
-            int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
-            ClipData data) {
-        return mDragDropController.performDrag(mSurfaceSession, window, dragToken, surface,
-                touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
-    }
-
-    @Override
     public void reportDropResult(IWindow window, boolean consumed) {
         final long ident = Binder.clearCallingIdentity();
         try {
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index 9a0d400..57da6a3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -20,7 +20,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
@@ -37,7 +36,6 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.InputChannel;
-import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.View;
@@ -148,12 +146,6 @@
     }
 
     @Test
-    public void testPrepareDrag_ZeroSizeSurface() throws Exception {
-        mToken = mTarget.prepareDrag(new SurfaceSession(), 0, 0, mWindow.mClient, 0, 0, 0);
-        assertNull(mToken);
-    }
-
-    @Test
     public void testPerformDrag_NullDataWithGrantUri() throws Exception {
         dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
     }
@@ -169,8 +161,6 @@
     }
 
     private void dragFlow(int flag, ClipData data, float dropX, float dropY) {
-        mToken = mTarget.prepareDrag(new SurfaceSession(), 0, 0, mWindow.mClient, flag, 100, 100);
-        assertNotNull(mToken);
         final SurfaceSession appSession = new SurfaceSession();
         try {
             final SurfaceControl surface = new SurfaceControl.Builder(appSession)
@@ -180,8 +170,10 @@
                     .build();
 
             assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
-            assertNotNull(mTarget.performDrag(
-                    new SurfaceSession(), mWindow.mClient, mToken, surface, 0, 0, 0, 0, 0, data));
+            mToken = mTarget.performDrag(
+                    new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
+                    data);
+            assertNotNull(mToken);
 
             mTarget.handleMotionEvent(false, dropX, dropY);
             mToken = mWindow.mClient.asBinder();