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

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

Merge changes I56d15881,Ifd031285

* changes:
  Move out DragInputEventReceiver from WindowManagerService
  Move drag related handler code to DragHandler
parents 3de63351 52cb2155
Loading
Loading
Loading
Loading
+117 −62
Original line number Diff line number Diff line
@@ -24,7 +24,9 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.content.ClipData;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Slog;
import android.view.Display;
@@ -33,7 +35,6 @@ import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
import com.android.server.wm.WindowManagerService.H;

/**
 * Managing drag and drop operations initiated by View#startDragAndDrop.
@@ -41,13 +42,28 @@ import com.android.server.wm.WindowManagerService.H;
class DragDropController {
    private static final float DRAG_SHADOW_ALPHA_TRANSPARENT = .7071f;
    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;

    DragState mDragState;

    private WindowManagerService mService;
    private final Handler mHandler;

    boolean dragDropActiveLocked() {
        return mDragState != null;
    }

    IBinder prepareDrag(WindowManagerService service, SurfaceSession session, int callerPid,
    DragDropController(WindowManagerService service, Looper looper) {
        mService = service;
        mHandler = new DragHandler(service, looper);
    }

    IBinder prepareDrag(SurfaceSession session, int callerPid,
            int callerUid, IWindow window, int flags, int width, int height, Surface outSurface) {
        if (DEBUG_DRAG) {
            Slog.d(TAG_WM, "prepare drag surface: w=" + width + " h=" + height
@@ -57,7 +73,7 @@ class DragDropController {

        IBinder token = null;

        synchronized (service.mWindowMap) {
        synchronized (mService.mWindowMap) {
            if (dragDropActiveLocked()) {
                Slog.w(TAG_WM, "Drag already in progress");
                return null;
@@ -65,7 +81,7 @@ class DragDropController {

            // TODO(multi-display): support other displays
            final DisplayContent displayContent =
                    service.getDefaultDisplayContentLocked();
                    mService.getDefaultDisplayContentLocked();
            final Display display = displayContent.getDisplay();

            final SurfaceControl surface = new SurfaceControl.Builder(session)
@@ -84,29 +100,27 @@ class DragDropController {
            outSurface.copyFrom(surface);
            final IBinder winBinder = window.asBinder();
            token = new Binder();
            mDragState = new DragState(service, token, surface, flags, winBinder);
            mDragState = new DragState(mService, 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
            service.mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
            Message msg = service.mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
            service.mH.sendMessageDelayed(msg, DRAG_TIMEOUT_MS);
            sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
        }

        return token;
    }

    boolean performDrag(WindowManagerService service, IWindow window, IBinder dragToken,
    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);
        }

        synchronized (service.mWindowMap) {
        synchronized (mService.mWindowMap) {
            if (mDragState == null) {
                Slog.w(TAG_WM, "No drag prepared");
                throw new IllegalStateException("performDrag() without prepareDrag()");
@@ -117,7 +131,7 @@ class DragDropController {
                throw new IllegalStateException("performDrag() does not match prepareDrag()");
            }

            final WindowState callingWin = service.windowForClientLocked(null, window, false);
            final WindowState callingWin = mService.windowForClientLocked(null, window, false);
            if (callingWin == null) {
                Slog.w(TAG_WM, "Bad requesting window " + window);
                return false;  // !!! TODO: throw here?
@@ -127,12 +141,12 @@ class DragDropController {
            // the drag initiation (e.g. an alarm window popped up just as the application
            // called performDrag()

            service.mH.removeMessages(H.DRAG_START_TIMEOUT, window.asBinder());
            mHandler.removeMessages(MSG_DRAG_START_TIMEOUT, window.asBinder());

            // !!! TODO: extract the current touch (x, y) in screen coordinates.  That
            // will let us eliminate the (touchX,touchY) parameters from the API.

            // !!! FIXME: put all this heavy stuff onto the mH looper, as well as
            // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
            // the actual drag event dispatch stuff in the dragstate

            final DisplayContent displayContent = callingWin.getDisplayContent();
@@ -141,7 +155,7 @@ class DragDropController {
            }
            Display display = displayContent.getDisplay();
            mDragState.register(display);
            if (!service.mInputManager.transferTouchFocus(callingWin.mInputChannel,
            if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
                    mDragState.getInputChannel())) {
                Slog.e(TAG_WM, "Unable to transfer touch focus");
                mDragState.unregister();
@@ -152,8 +166,8 @@ class DragDropController {

            mDragState.mDisplayContent = displayContent;
            mDragState.mData = data;
            mDragState.broadcastDragStartedLw(touchX, touchY);
            mDragState.overridePointerIconLw(touchSource);
            mDragState.broadcastDragStartedLocked(touchX, touchY);
            mDragState.overridePointerIconLocked(touchSource);

            // remember the thumb offsets for later
            mDragState.mThumbOffsetX = thumbCenterX;
@@ -163,32 +177,32 @@ class DragDropController {
            final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                    TAG_WM, ">>> OPEN TRANSACTION performDrag");
            service.openSurfaceTransaction();
            mService.openSurfaceTransaction();
            try {
                surfaceControl.setPosition(touchX - thumbCenterX,
                        touchY - thumbCenterY);
                surfaceControl.setLayer(mDragState.getDragLayerLw());
                surfaceControl.setLayer(mDragState.getDragLayerLocked());
                surfaceControl.setLayerStack(display.getLayerStack());
                surfaceControl.show();
            } finally {
                service.closeSurfaceTransaction();
                mService.closeSurfaceTransaction();
                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                        TAG_WM, "<<< CLOSE TRANSACTION performDrag");
            }

            mDragState.notifyLocationLw(touchX, touchY);
            mDragState.notifyLocationLocked(touchX, touchY);
        }

        return true;    // success!
    }

    void reportDropResult(WindowManagerService service, IWindow window, boolean consumed) {
    void reportDropResult(IWindow window, boolean consumed) {
        IBinder token = window.asBinder();
        if (DEBUG_DRAG) {
            Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token);
        }

        synchronized (service.mWindowMap) {
        synchronized (mService.mWindowMap) {
            if (mDragState == null) {
                // Most likely the drop recipient ANRed and we ended the drag
                // out from under it.  Log the issue and move on.
@@ -205,24 +219,24 @@ class DragDropController {
            // The right window has responded, even if it's no longer around,
            // so be sure to halt the timeout even if the later WindowState
            // lookup fails.
            service.mH.removeMessages(H.DRAG_END_TIMEOUT, window.asBinder());
            WindowState callingWin = service.windowForClientLocked(null, window, false);
            mHandler.removeMessages(MSG_DRAG_END_TIMEOUT, window.asBinder());
            WindowState callingWin = mService.windowForClientLocked(null, window, false);
            if (callingWin == null) {
                Slog.w(TAG_WM, "Bad result-reporting window " + window);
                return;  // !!! TODO: throw here?
            }

            mDragState.mDragResult = consumed;
            mDragState.endDragLw();
            mDragState.endDragLocked();
        }
    }

    void cancelDragAndDrop(WindowManagerService service, IBinder dragToken) {
    void cancelDragAndDrop(IBinder dragToken) {
        if (DEBUG_DRAG) {
            Slog.d(TAG_WM, "cancelDragAndDrop");
        }

        synchronized (service.mWindowMap) {
        synchronized (mService.mWindowMap) {
            if (mDragState == null) {
                Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
                throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()");
@@ -236,7 +250,7 @@ class DragDropController {
            }

            mDragState.mDragResult = false;
            mDragState.cancelDragLw();
            mDragState.cancelDragLocked();
        }
    }

@@ -252,14 +266,42 @@ class DragDropController {
        }
    }

    void handleMessage(WindowManagerService service, Message msg) {
    /**
     * Sends a message to the Handler managed by DragDropController.
     */
    void sendHandlerMessage(int what, Object arg) {
        mHandler.obtainMessage(what, arg).sendToTarget();
    }

    /**
     * Sends a timeout message to the Handler managed by DragDropController.
     */
    void sendTimeoutMessage(int what, Object arg) {
        mHandler.removeMessages(what, arg);
        final Message msg = mHandler.obtainMessage(what, arg);
        mHandler.sendMessageDelayed(msg, DRAG_TIMEOUT_MS);
    }

    private class DragHandler extends Handler {
        /**
         * Lock for window manager.
         */
        private final WindowManagerService mService;

        DragHandler(WindowManagerService service, Looper looper) {
            super(looper);
            mService = service;
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case H.DRAG_START_TIMEOUT: {
                case MSG_DRAG_START_TIMEOUT: {
                    IBinder win = (IBinder) msg.obj;
                    if (DEBUG_DRAG) {
                        Slog.w(TAG_WM, "Timeout starting drag by win " + win);
                    }
                synchronized (service.mWindowMap) {
                    synchronized (mService.mWindowMap) {
                        // !!! TODO: ANR the app that has failed to start the drag in time
                        if (mDragState != null) {
                            mDragState.unregister();
@@ -270,32 +312,45 @@ class DragDropController {
                    break;
                }

            case H.DRAG_END_TIMEOUT: {
                case MSG_DRAG_END_TIMEOUT: {
                    IBinder win = (IBinder) msg.obj;
                    if (DEBUG_DRAG) {
                        Slog.w(TAG_WM, "Timeout ending drag to win " + win);
                    }
                synchronized (service.mWindowMap) {
                    synchronized (mService.mWindowMap) {
                        // !!! TODO: ANR the drag-receiving app
                        if (mDragState != null) {
                            mDragState.mDragResult = false;
                        mDragState.endDragLw();
                            mDragState.endDragLocked();
                        }
                    }
                    break;
                }

            case H.TEAR_DOWN_DRAG_AND_DROP_INPUT: {
                case MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT: {
                    if (DEBUG_DRAG)
                        Slog.d(TAG_WM, "Drag ending; tearing down input channel");
                    DragState.InputInterceptor interceptor = (DragState.InputInterceptor) msg.obj;
                    if (interceptor != null) {
                    synchronized (service.mWindowMap) {
                        synchronized (mService.mWindowMap) {
                            interceptor.tearDown();
                        }
                    }
                    break;
                }

                case MSG_ANIMATION_END: {
                    synchronized (mService.mWindowMap) {
                        if (mDragState == null) {
                            Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
                                    "plyaing animation");
                            return;
                        }
                        mDragState.onAnimationEndLocked();
                    }
                    break;
                }
            }
        }
    }
}
+151 −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 com.android.server.wm;

import static android.view.InputDevice.SOURCE_CLASS_POINTER;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.BUTTON_STYLUS_PRIMARY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;

import android.os.Looper;
import android.util.Slog;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.MotionEvent;

/**
 * Input receiver for drag and drop
 */
class DragInputEventReceiver extends InputEventReceiver {
    private final WindowManagerService mService;
    private final DragDropController mDragDropController;

    // Set, if stylus button was down at the start of the drag.
    private boolean mStylusButtonDownAtStart;
    // Indicates the first event to check for button state.
    private boolean mIsStartEvent = true;
    // Set to true to ignore input events after the drag gesture is complete but the drag events
    // are still being dispatched.
    private boolean mMuteInput = false;

    public DragInputEventReceiver(InputChannel inputChannel, Looper looper,
            DragDropController controller, WindowManagerService service) {
        super(inputChannel, looper);
        mDragDropController = controller;
        mService = service;
    }

    @Override
    public void onInputEvent(InputEvent event, int displayId) {
        boolean handled = false;
        try {
            synchronized (mService.mWindowMap) {
                if (!mDragDropController.dragDropActiveLocked()) {
                    // The drag has ended but the clean-up message has not been processed by
                    // window manager. Drop events that occur after this until window manager
                    // has a chance to clean-up the input handle.
                    handled = true;
                    return;
                }
                if (!(event instanceof MotionEvent)
                        || (event.getSource() & SOURCE_CLASS_POINTER) == 0
                        || mMuteInput) {
                    return;
                }
                final MotionEvent motionEvent = (MotionEvent) event;
                boolean endDrag = false;
                final float newX = motionEvent.getRawX();
                final float newY = motionEvent.getRawY();
                final boolean isStylusButtonDown =
                        (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0;

                if (mIsStartEvent) {
                    if (isStylusButtonDown) {
                        // First event and the button was down, check for the button being
                        // lifted in the future, if that happens we'll drop the item.
                        mStylusButtonDownAtStart = true;
                    }
                    mIsStartEvent = false;
                }

                switch (motionEvent.getAction()) {
                    case ACTION_DOWN: {
                        if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer");
                    }
                    break;

                    case ACTION_MOVE: {
                        if (mStylusButtonDownAtStart && !isStylusButtonDown) {
                            if (DEBUG_DRAG) {
                                Slog.d(TAG_WM, "Button no longer pressed; dropping at "
                                        + newX + "," + newY);
                            }
                            mMuteInput = true;
                            endDrag = mDragDropController.mDragState
                                    .notifyDropLocked(newX, newY);
                        } else {
                            // move the surface and tell the involved window(s) where we are
                            mDragDropController.mDragState.notifyMoveLocked(newX, newY);
                        }
                    }
                    break;

                    case ACTION_UP: {
                        if (DEBUG_DRAG) {
                            Slog.d(TAG_WM, "Got UP on move channel; dropping at "
                                    + newX + "," + newY);
                        }
                        mMuteInput = true;
                        endDrag = mDragDropController.mDragState
                                .notifyDropLocked(newX, newY);
                    }
                    break;

                    case ACTION_CANCEL: {
                        if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!");
                        mMuteInput = true;
                        endDrag = true;
                    }
                    break;
                }

                if (endDrag) {
                    if (DEBUG_DRAG)
                        Slog.d(TAG_WM, "Drag ended; tearing down state");
                    // tell all the windows that the drag has ended
                    // endDragLocked will post back to looper to dispose the receiver
                    // since we still need the receiver for the last finishInputEvent.
                    mDragDropController.mDragState.endDragLocked();
                    mStylusButtonDownAtStart = false;
                    mIsStartEvent = true;
                }

                handled = true;
            }
        } catch (Exception e) {
            Slog.e(TAG_WM, "Exception caught by drag handleMotion", e);
        } finally {
            finishInputEvent(event, handled);
        }
    }
}
+43 −72

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -690,7 +690,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
            // If there's a drag in progress and 'child' is a potential drop target,
            // make sure it's been told about the drag
            if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) {
                mService.mDragDropController.mDragState.sendDragStartedIfNeededLw(w);
                mService.mDragDropController.mDragState.sendDragStartedIfNeededLocked(w);
            }

            addInputWindowHandle(
+4 −4
Original line number Diff line number Diff line
@@ -313,7 +313,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
        final long ident = Binder.clearCallingIdentity();
        try {
            return mDragDropController.prepareDrag(
                    mService, mSurfaceSession, callerPid, callerUid, window, flags, width, height,
                    mSurfaceSession, callerPid, callerUid, window, flags, width, height,
                    outSurface);
        } finally {
            Binder.restoreCallingIdentity(ident);
@@ -324,7 +324,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    public boolean performDrag(IWindow window, IBinder dragToken,
            int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
            ClipData data) {
        return mDragDropController.performDrag(mService, window, dragToken, touchSource,
        return mDragDropController.performDrag(window, dragToken, touchSource,
                touchX, touchY, thumbCenterX, thumbCenterY, data);
    }

@@ -332,7 +332,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    public void reportDropResult(IWindow window, boolean consumed) {
        final long ident = Binder.clearCallingIdentity();
        try {
            mDragDropController.reportDropResult(mService, window, consumed);
            mDragDropController.reportDropResult(window, consumed);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
@@ -342,7 +342,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    public void cancelDragAndDrop(IBinder dragToken) {
        final long ident = Binder.clearCallingIdentity();
        try {
            mDragDropController.cancelDragAndDrop(mService, dragToken);
            mDragDropController.cancelDragAndDrop(dragToken);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
Loading