diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index ed167c812be18..a7112ba09fed8 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -29,6 +29,7 @@ import android.view.IWindowId; import android.view.MotionEvent; import android.view.WindowManager; import android.view.Surface; +import android.view.SurfaceControl; /** * System private per-application interface to the window manager. @@ -154,21 +155,21 @@ interface IWindowSession { * 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, out Surface outSurface); + IBinder prepareDrag(IWindow window, int flags, int thumbnailWidth, int thumbnailHeight); /** * Initiate the drag operation itself */ - boolean performDrag(IWindow window, IBinder dragToken, int touchSource, - float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data); + boolean performDrag(IWindow window, IBinder dragToken, 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. * consumed is 'true' when the drop was accepted by a valid recipient, * 'false' otherwise. */ - void reportDropResult(IWindow window, boolean consumed); + void reportDropResult(IWindow window, boolean consumed); /** * Cancel the current drag operation. diff --git a/core/java/android/view/SurfaceControl.aidl b/core/java/android/view/SurfaceControl.aidl new file mode 100644 index 0000000000000..744ead2be6432 --- /dev/null +++ b/core/java/android/view/SurfaceControl.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +parcelable SurfaceControl; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0bf690457e1e9..34ad91c717475 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -23502,9 +23502,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Point shadowTouchPoint = new Point(); shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); - if ((shadowSize.x < 0) || (shadowSize.y < 0) || - (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { - throw new IllegalStateException("Drag shadow dimensions must not be negative"); + if ((shadowSize.x <= 0) || (shadowSize.y <= 0) + || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { + throw new IllegalStateException("Drag shadow dimensions must be positive"); } if (ViewDebug.DEBUG_DRAG) { @@ -23515,13 +23515,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mAttachInfo.mDragSurface.release(); } mAttachInfo.mDragSurface = new Surface(); + + final ViewRootImpl root = mAttachInfo.mViewRootImpl; + final SurfaceSession session = new SurfaceSession(root.mSurface); try { mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, - flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); + 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) { - Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(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); @@ -23529,23 +23538,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); } - final ViewRootImpl root = getViewRootImpl(); - // 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, - root.getLastTouchSource(), shadowSize.x, shadowSize.y, - shadowTouchPoint.x, shadowTouchPoint.y, data); + 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); } } catch (Exception e) { Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); mAttachInfo.mDragSurface.destroy(); mAttachInfo.mDragSurface = null; + } finally { + session.kill(); } return okay; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index a8e00dd53526f..77367db94e356 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 @@ class DisplayContent extends WindowContainer>> 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 192d6c84e1909..928062086d777 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.IWindowSession; 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 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { /* 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 ac291632c8772..9a0d40038403c 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.spy; 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.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; import com.android.internal.annotations.GuardedBy; @@ -147,9 +149,7 @@ public class DragDropControllerTests extends WindowTestsBase { @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 @@ public class DragDropControllerTests extends WindowTestsBase { } 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(); + } } }