Create a drag shadow surface in app process,

Previoulsy a drag shadow surface is created in the system process. App needs
to call one more binder call (prepareDrag) to obtain the surface from
the system process.

The CL lets an app to create a drag shadow surface by itself. Then app
transfer the surface to system server by using reparent
API.

Bug: 70818582
Test: com.android.server.wm.DragDropControllerTests,
      android.server.wm.CrossAppDragAndDropTests,
      manually check the drag and drop behavior on test app.
Change-Id: I72796efffbefe78a802d7c441dea308d1cdea572
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a8e00dd..77367db 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3690,6 +3690,13 @@
             .setParent(mOverlayLayer);
     }
 
+    /**
+     * Reparents the given surface to mOverlayLayer.
+     */
+    void reparentToOverlay(Transaction transaction, SurfaceControl surface) {
+        transaction.reparent(surface, mOverlayLayer.getHandle());
+    }
+
     void applyMagnificationSpec(MagnificationSpec spec) {
         applyMagnificationSpec(getPendingTransaction(), spec);
         getPendingTransaction().apply();
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 0171b56..bf97bd2 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -18,12 +18,10 @@
 
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
 import android.content.ClipData;
-import android.graphics.PixelFormat;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -32,8 +30,8 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.IWindow;
-import android.view.Surface;
 import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
 import android.view.View;
 
@@ -96,7 +94,7 @@
     }
 
     IBinder prepareDrag(SurfaceSession session, int callerPid,
-            int callerUid, IWindow window, int flags, int width, int height, Surface outSurface) {
+            int callerUid, IWindow window, int flags, int width, int height) {
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "prepare drag surface: w=" + width + " h=" + height
                     + " flags=" + Integer.toHexString(flags) + " win=" + window
@@ -115,28 +113,13 @@
             }
 
             // TODO(multi-display): support other displays
-            final DisplayContent displayContent =
-                    mService.getDefaultDisplayContentLocked();
-            final Display display = displayContent.getDisplay();
-
-            final SurfaceControl surface = new SurfaceControl.Builder(session)
-                    .setName("drag surface")
-                    .setSize(width, height)
-                    .setFormat(PixelFormat.TRANSLUCENT)
-                    .build();
-            surface.setLayerStack(display.getLayerStack());
             float alpha = 1;
             if ((flags & View.DRAG_FLAG_OPAQUE) == 0) {
                 alpha = DRAG_SHADOW_ALPHA_TRANSPARENT;
             }
-            surface.setAlpha(alpha);
-
-            if (SHOW_TRANSACTIONS)
-                Slog.i(TAG_WM, "  DRAG " + surface + ": CREATE");
-            outSurface.copyFrom(surface);
             final IBinder winBinder = window.asBinder();
             IBinder token = new Binder();
-            mDragState = new DragState(mService, this, token, surface, flags, winBinder);
+            mDragState = new DragState(mService, this, token, /* surface */ null, flags, winBinder);
             mDragState.mPid = callerPid;
             mDragState.mUid = callerUid;
             mDragState.mOriginalAlpha = alpha;
@@ -148,9 +131,9 @@
         }
     }
 
-    boolean performDrag(IWindow window, IBinder dragToken,
-            int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
-            ClipData data) {
+    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);
         }
@@ -202,6 +185,8 @@
                         return false;
                     }
 
+                    mDragState.mSurfaceControl = surface;
+                    surface = null;
                     mDragState.mDisplayContent = displayContent;
                     mDragState.mData = data;
                     mDragState.broadcastDragStartedLocked(touchX, touchY);
@@ -213,22 +198,25 @@
                     // Make the surface visible at the proper location
                     final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
                     if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
-                    mService.openSurfaceTransaction();
-                    try {
-                        surfaceControl.setPosition(touchX - thumbCenterX,
-                                touchY - thumbCenterY);
-                        surfaceControl.setLayer(mDragState.getDragLayerLocked());
-                        surfaceControl.setLayerStack(display.getLayerStack());
-                        surfaceControl.show();
-                    } finally {
-                        mService.closeSurfaceTransaction("performDrag");
-                        if (SHOW_LIGHT_TRANSACTIONS) {
-                            Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
-                        }
+
+                    final SurfaceControl.Transaction transaction =
+                            callingWin.getPendingTransaction();
+                    transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
+                    transaction.setPosition(
+                            surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY);
+                    transaction.show(surfaceControl);
+                    displayContent.reparentToOverlay(transaction, surfaceControl);
+                    callingWin.scheduleAnimation();
+
+                    if (SHOW_LIGHT_TRANSACTIONS) {
+                        Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
                     }
 
                     mDragState.notifyLocationLocked(touchX, touchY);
                 } finally {
+                    if (surface != null) {
+                        surface.release();
+                    }
                     if (mDragState != null && !mDragState.isInProgress()) {
                         mDragState.closeLocked();
                     }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 192d6c8..9280620 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -51,6 +51,7 @@
 import android.view.IWindowSessionCallback;
 import android.view.InputChannel;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.WindowManager;
 
@@ -309,26 +310,24 @@
 
     /* Drag/drop */
     @Override
-    public IBinder prepareDrag(IWindow window, int flags, int width, int height,
-            Surface outSurface) {
+    public IBinder prepareDrag(IWindow window, int flags, int width, int height) {
         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,
-                    outSurface);
+            return mDragDropController.prepareDrag(mSurfaceSession, callerPid, callerUid, window,
+                    flags, width, height);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override
-    public boolean performDrag(IWindow window, IBinder dragToken,
+    public boolean performDrag(IWindow window, IBinder dragToken, SurfaceControl surface,
             int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
             ClipData data) {
-        return mDragDropController.performDrag(window, dragToken, touchSource,
-                touchX, touchY, thumbCenterX, thumbCenterY, data);
+        return mDragDropController.performDrag(mSurfaceSession, window, dragToken, surface,
+                touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
     }
 
     @Override
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 ac29163..9a0d400 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.ClipData;
+import android.graphics.PixelFormat;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -37,6 +38,7 @@
 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;
 import com.android.internal.annotations.GuardedBy;
@@ -147,9 +149,7 @@
 
     @Test
     public void testPrepareDrag_ZeroSizeSurface() throws Exception {
-        final Surface surface = new Surface();
-        mToken = mTarget.prepareDrag(
-                new SurfaceSession(), 0, 0, mWindow.mClient, 0, 0, 0, surface);
+        mToken = mTarget.prepareDrag(new SurfaceSession(), 0, 0, mWindow.mClient, 0, 0, 0);
         assertNull(mToken);
     }
 
@@ -169,16 +169,24 @@
     }
 
     private void dragFlow(int flag, ClipData data, float dropX, float dropY) {
-        final Surface surface = new Surface();
-        mToken = mTarget.prepareDrag(
-                new SurfaceSession(), 0, 0, mWindow.mClient, flag, 100, 100, surface);
+        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)
+                    .setName("drag surface")
+                    .setSize(100, 100)
+                    .setFormat(PixelFormat.TRANSLUCENT)
+                    .build();
 
-        assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
-        assertTrue(mTarget.performDrag(
-                mWindow.mClient, mToken, 0, 0, 0, 0, 0, data));
+            assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
+            assertNotNull(mTarget.performDrag(
+                    new SurfaceSession(), mWindow.mClient, mToken, surface, 0, 0, 0, 0, 0, data));
 
-        mTarget.handleMotionEvent(false, dropX, dropY);
-        mToken = mWindow.mClient.asBinder();
+            mTarget.handleMotionEvent(false, dropX, dropY);
+            mToken = mWindow.mClient.asBinder();
+        } finally {
+            appSession.kill();
+        }
     }
 }