diff options
| author | 2018-01-19 01:24:40 +0000 | |
|---|---|---|
| committer | 2018-01-19 01:24:40 +0000 | |
| commit | 07f35aa6165c7abd418faf3b419bc1a003f6d992 (patch) | |
| tree | 8e18d0dd37c25747b72cfd89d876a32614d55379 | |
| parent | 22b111da8b41f5f5962d1a37725cb58db44577c5 (diff) | |
| parent | fabca09f0f5cf32eeebb4c8ae793f498aa182d58 (diff) | |
Merge changes from topic "shadow-in-app"
* changes:
Remove DragDropController#prepareDrag()
Create a drag shadow surface in app process,
7 files changed, 160 insertions, 179 deletions
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 49f14442868b..17b6ddca6394 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. @@ -150,25 +151,32 @@ interface IWindowSession { 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, out Surface outSurface); - - /** * Initiate the drag operation itself - */ - boolean performDrag(IWindow window, IBinder dragToken, int touchSource, + * + * @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. + */ + 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. * 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 000000000000..744ead2be643 --- /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 3242ff1a0b90..05770c357526 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -23562,15 +23562,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); } - boolean okay = false; - Point shadowSize = new Point(); 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) { @@ -23581,40 +23579,50 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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, mAttachInfo.mDragSurface); - 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); - try { - canvas.drawColor(0, PorterDuff.Mode.CLEAR); - shadowBuilder.onDrawShadow(canvas); - } finally { - mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); - } - - final ViewRootImpl root = getViewRootImpl(); + 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); + // Cache the local state object for delivery with DragEvents + root.setLocalDragState(myLocalState); - // repurpose 'shadowSize' for the last touch point - root.getLastTouchPoint(shadowSize); + // 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); - if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); + 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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 3997c56eec07..fba404ed6f0e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3697,6 +3697,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo .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 0171b56ffc47..d55a64926504 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 @@ package com.android.server.wm; 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.os.Message; 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; @@ -50,10 +48,9 @@ class DragDropController { 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. @@ -95,87 +92,35 @@ class DragDropController { mDragState.sendDragStartedIfNeededLocked(window); } - IBinder prepareDrag(SurfaceSession session, int callerPid, - int callerUid, IWindow window, int flags, int width, int height, Surface outSurface) { + 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()); - } - - 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 - 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.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(IWindow window, IBinder dragToken, - 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); + Slog.d(TAG_WM, "perform drag: win=" + window + " surface=" + surface + " flags=" + + Integer.toHexString(flags) + " 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 @@ -188,18 +133,31 @@ class DragDropController { // !!! 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.mDisplayContent = displayContent; @@ -213,28 +171,31 @@ class DragDropController { // 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(); } } } - return true; // success! + return dragToken; // success! } finally { mCallback.get().postPerformDrag(); } @@ -385,21 +346,6 @@ class DragDropController { @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 334be336e199..04ae38ec33b1 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; @@ -308,30 +309,22 @@ 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 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, - outSurface); + 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, - int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY, - ClipData data) { - return mDragDropController.performDrag(window, dragToken, 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 ac291632c877..57da6a3a60a6 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.ACTIVITY_TYPE_STANDARD; 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; @@ -28,6 +27,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; @@ -36,7 +36,7 @@ import android.platform.test.annotations.Presubmit; 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; @@ -146,14 +146,6 @@ 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); - assertNull(mToken); - } - - @Test public void testPerformDrag_NullDataWithGrantUri() throws Exception { dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0); } @@ -169,16 +161,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); - assertNotNull(mToken); - - assertTrue(sWm.mInputManager.transferTouchFocus(null, null)); - assertTrue(mTarget.performDrag( - mWindow.mClient, mToken, 0, 0, 0, 0, 0, data)); - - mTarget.handleMotionEvent(false, dropX, dropY); - mToken = mWindow.mClient.asBinder(); + 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)); + 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(); + } finally { + appSession.kill(); + } } } |