Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07f35aa6 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "shadow-in-app"

* changes:
  Remove DragDropController#prepareDrag()
  Create a drag shadow surface in app process,
parents 22b111da fabca09f
Loading
Loading
Loading
Loading
+20 −12
Original line number Diff line number Diff line
@@ -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.
@@ -149,18 +150,25 @@ 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);

    /**
+19 −0
Original line number Diff line number Diff line
/*
 * 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;
+39 −31
Original line number Diff line number Diff line
@@ -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,13 +23579,18 @@ 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);
            mAttachInfo.mDragSurface.copyFrom(surface);
            final Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
            try {
                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
                shadowBuilder.onDrawShadow(canvas);
@@ -23595,26 +23598,31 @@ 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);
                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);
            return false;
        } finally {
            if (mAttachInfo.mDragToken == null) {
                mAttachInfo.mDragSurface.destroy();
                mAttachInfo.mDragSurface = null;
                root.setLocalDragState(null);
            }
            session.kill();
        }
        return okay;
    }
    /**
+7 −0
Original line number Diff line number Diff line
@@ -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();
+48 −102
Original line number Diff line number Diff line
@@ -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");

                    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) {
Loading