FileDocCategorySizeDatePackage
DragState.javaAPI DocAndroid 5.1 API17841Thu Mar 12 22:22:42 GMT 2015com.android.server.wm

DragState

public class DragState extends Object
Drag/drop state

Fields Summary
final WindowManagerService
mService
android.os.IBinder
mToken
android.view.SurfaceControl
mSurfaceControl
int
mFlags
android.os.IBinder
mLocalWin
android.content.ClipData
mData
android.content.ClipDescription
mDataDescription
boolean
mDragResult
float
mCurrentX
float
mCurrentY
float
mThumbOffsetX
float
mThumbOffsetY
android.view.InputChannel
mServerChannel
android.view.InputChannel
mClientChannel
com.android.server.wm.WindowManagerService.DragInputEventReceiver
mInputEventReceiver
com.android.server.input.InputApplicationHandle
mDragApplicationHandle
com.android.server.input.InputWindowHandle
mDragWindowHandle
WindowState
mTargetWindow
ArrayList
mNotifiedWindows
boolean
mDragInProgress
android.view.Display
mDisplay
private final android.graphics.Region
mTmpRegion
Constructors Summary
DragState(WindowManagerService service, android.os.IBinder token, android.view.SurfaceControl surface, int flags, android.os.IBinder localWin)


         
                
        mService = service;
        mToken = token;
        mSurfaceControl = surface;
        mFlags = flags;
        mLocalWin = localWin;
        mNotifiedWindows = new ArrayList<WindowState>();
    
Methods Summary
voidbroadcastDragEndedLw()

        if (WindowManagerService.DEBUG_DRAG) {
            Slog.d(WindowManagerService.TAG, "broadcasting DRAG_ENDED");
        }
        DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
                0, 0, null, null, null, mDragResult);
        for (WindowState ws: mNotifiedWindows) {
            try {
                ws.mClient.dispatchDragEvent(evt);
            } catch (RemoteException e) {
                Slog.w(WindowManagerService.TAG, "Unable to drag-end window " + ws);
            }
        }
        mNotifiedWindows.clear();
        mDragInProgress = false;
        evt.recycle();
    
voidbroadcastDragStartedLw(float touchX, float touchY)

        // Cache a base-class instance of the clip metadata so that parceling
        // works correctly in calling out to the apps.
        mDataDescription = (mData != null) ? mData.getDescription() : null;
        mNotifiedWindows.clear();
        mDragInProgress = true;

        if (WindowManagerService.DEBUG_DRAG) {
            Slog.d(WindowManagerService.TAG, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
        }

        final WindowList windows = mService.getWindowListLocked(mDisplay);
        if (windows != null) {
            final int N = windows.size();
            for (int i = 0; i < N; i++) {
                sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
            }
        }
    
voidendDragLw()

        mService.mDragState.broadcastDragEndedLw();

        // stop intercepting input
        mService.mDragState.unregister();
        mService.mInputMonitor.updateInputWindowsLw(true /*force*/);

        // free our resources and drop all the object references
        mService.mDragState.reset();
        mService.mDragState = null;
    
intgetDragLayerLw()

        return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG)
                * WindowManagerService.TYPE_LAYER_MULTIPLIER
                + WindowManagerService.TYPE_LAYER_OFFSET;
    
private WindowStategetTouchedWinAtPointLw(float xf, float yf)

        WindowState touchedWin = null;
        final int x = (int) xf;
        final int y = (int) yf;

        final WindowList windows = mService.getWindowListLocked(mDisplay);
        if (windows == null) {
            return null;
        }
        final int N = windows.size();
        for (int i = N - 1; i >= 0; i--) {
            WindowState child = windows.get(i);
            final int flags = child.mAttrs.flags;
            if (!child.isVisibleLw()) {
                // not visible == don't tell about drags
                continue;
            }
            if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
                // not touchable == don't tell about drags
                continue;
            }

            child.getTouchableRegion(mTmpRegion);

            final int touchFlags = flags &
                    (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
            if (mTmpRegion.contains(x, y) || touchFlags == 0) {
                // Found it
                touchedWin = child;
                break;
            }
        }

        return touchedWin;
    
booleannotifyDropLw(float x, float y)

        WindowState touchedWin = getTouchedWinAtPointLw(x, y);
        if (touchedWin == null) {
            // "drop" outside a valid window -- no recipient to apply a
            // timeout to, and we can send the drag-ended message immediately.
            mDragResult = false;
            return true;
        }

        if (WindowManagerService.DEBUG_DRAG) {
            Slog.d(WindowManagerService.TAG, "sending DROP to " + touchedWin);
        }
        final int myPid = Process.myPid();
        final IBinder token = touchedWin.mClient.asBinder();
        DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
                null, null, mData, false);
        try {
            touchedWin.mClient.dispatchDragEvent(evt);

            // 5 second timeout for this window to respond to the drop
            mService.mH.removeMessages(H.DRAG_END_TIMEOUT, token);
            Message msg = mService.mH.obtainMessage(H.DRAG_END_TIMEOUT, token);
            mService.mH.sendMessageDelayed(msg, 5000);
        } catch (RemoteException e) {
            Slog.w(WindowManagerService.TAG, "can't send drop notification to win " + touchedWin);
            return true;
        } finally {
            if (myPid != touchedWin.mSession.mPid) {
                evt.recycle();
            }
        }
        mToken = token;
        return false;
    
voidnotifyMoveLw(float x, float y)

        final int myPid = Process.myPid();

        // Move the surface to the given touch
        if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(
                WindowManagerService.TAG, ">>> OPEN TRANSACTION notifyMoveLw");
        SurfaceControl.openTransaction();
        try {
            mSurfaceControl.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DRAG "
                    + mSurfaceControl + ": pos=(" +
                    (int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")");
        } finally {
            SurfaceControl.closeTransaction();
            if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(
                    WindowManagerService.TAG, "<<< CLOSE TRANSACTION notifyMoveLw");
        }

        // Tell the affected window
        WindowState touchedWin = getTouchedWinAtPointLw(x, y);
        if (touchedWin == null) {
            if (WindowManagerService.DEBUG_DRAG) Slog.d(WindowManagerService.TAG, "No touched win at x=" + x + " y=" + y);
            return;
        }
        if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
            final IBinder touchedBinder = touchedWin.mClient.asBinder();
            if (touchedBinder != mLocalWin) {
                // This drag is pinned only to the originating window, but the drag
                // point is outside that window.  Pretend it's over empty space.
                touchedWin = null;
            }
        }
        try {
            // have we dragged over a new window?
            if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
                if (WindowManagerService.DEBUG_DRAG) {
                    Slog.d(WindowManagerService.TAG, "sending DRAG_EXITED to " + mTargetWindow);
                }
                // force DRAG_EXITED_EVENT if appropriate
                DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
                        x, y, null, null, null, false);
                mTargetWindow.mClient.dispatchDragEvent(evt);
                if (myPid != mTargetWindow.mSession.mPid) {
                    evt.recycle();
                }
            }
            if (touchedWin != null) {
                if (false && WindowManagerService.DEBUG_DRAG) {
                    Slog.d(WindowManagerService.TAG, "sending DRAG_LOCATION to " + touchedWin);
                }
                DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
                        x, y, null, null, null, false);
                touchedWin.mClient.dispatchDragEvent(evt);
                if (myPid != touchedWin.mSession.mPid) {
                    evt.recycle();
                }
            }
        } catch (RemoteException e) {
            Slog.w(WindowManagerService.TAG, "can't send drag notification to windows");
        }
        mTargetWindow = touchedWin;
    
private static android.view.DragEventobtainDragEvent(WindowState win, int action, float x, float y, java.lang.Object localState, android.content.ClipDescription description, android.content.ClipData data, boolean result)

        float winX = x - win.mFrame.left;
        float winY = y - win.mFrame.top;
        if (win.mEnforceSizeCompat) {
            winX *= win.mGlobalScale;
            winY *= win.mGlobalScale;
        }
        return DragEvent.obtain(action, winX, winY, localState, description, data, result);
    
voidregister(android.view.Display display)

param
display The Display that the window being dragged is on.

        mDisplay = display;
        if (WindowManagerService.DEBUG_DRAG) Slog.d(WindowManagerService.TAG, "registering drag input channel");
        if (mClientChannel != null) {
            Slog.e(WindowManagerService.TAG, "Duplicate register of drag input channel");
        } else {
            InputChannel[] channels = InputChannel.openInputChannelPair("drag");
            mServerChannel = channels[0];
            mClientChannel = channels[1];
            mService.mInputManager.registerInputChannel(mServerChannel, null);
            mInputEventReceiver = mService.new DragInputEventReceiver(mClientChannel,
                    mService.mH.getLooper());

            mDragApplicationHandle = new InputApplicationHandle(null);
            mDragApplicationHandle.name = "drag";
            mDragApplicationHandle.dispatchingTimeoutNanos =
                    WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;

            mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
                    mDisplay.getDisplayId());
            mDragWindowHandle.name = "drag";
            mDragWindowHandle.inputChannel = mServerChannel;
            mDragWindowHandle.layer = getDragLayerLw();
            mDragWindowHandle.layoutParamsFlags = 0;
            mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
            mDragWindowHandle.dispatchingTimeoutNanos =
                    WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
            mDragWindowHandle.visible = true;
            mDragWindowHandle.canReceiveKeys = false;
            mDragWindowHandle.hasFocus = true;
            mDragWindowHandle.hasWallpaper = false;
            mDragWindowHandle.paused = false;
            mDragWindowHandle.ownerPid = Process.myPid();
            mDragWindowHandle.ownerUid = Process.myUid();
            mDragWindowHandle.inputFeatures = 0;
            mDragWindowHandle.scaleFactor = 1.0f;

            // The drag window cannot receive new touches.
            mDragWindowHandle.touchableRegion.setEmpty();

            // The drag window covers the entire display
            mDragWindowHandle.frameLeft = 0;
            mDragWindowHandle.frameTop = 0;
            Point p = new Point();
            mDisplay.getRealSize(p);
            mDragWindowHandle.frameRight = p.x;
            mDragWindowHandle.frameBottom = p.y;

            // Pause rotations before a drag.
            if (WindowManagerService.DEBUG_ORIENTATION) {
                Slog.d(WindowManagerService.TAG, "Pausing rotation during drag");
            }
            mService.pauseRotationLocked();
        }
    
voidreset()

        if (mSurfaceControl != null) {
            mSurfaceControl.destroy();
        }
        mSurfaceControl = null;
        mFlags = 0;
        mLocalWin = null;
        mToken = null;
        mData = null;
        mThumbOffsetX = mThumbOffsetY = 0;
        mNotifiedWindows = null;
    
voidsendDragStartedIfNeededLw(WindowState newWin)

        if (mDragInProgress) {
            // If we have sent the drag-started, we needn't do so again
            for (WindowState ws : mNotifiedWindows) {
                if (ws == newWin) {
                    return;
                }
            }
            if (WindowManagerService.DEBUG_DRAG) {
                Slog.d(WindowManagerService.TAG, "need to send DRAG_STARTED to new window " + newWin);
            }
            sendDragStartedLw(newWin, mCurrentX, mCurrentY, mDataDescription);
        }
    
private voidsendDragStartedLw(WindowState newWin, float touchX, float touchY, android.content.ClipDescription desc)

        // Don't actually send the event if the drag is supposed to be pinned
        // to the originating window but 'newWin' is not that window.
        if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0) {
            final IBinder winBinder = newWin.mClient.asBinder();
            if (winBinder != mLocalWin) {
                if (WindowManagerService.DEBUG_DRAG) {
                    Slog.d(WindowManagerService.TAG, "Not dispatching local DRAG_STARTED to " + newWin);
                }
                return;
            }
        }

        if (mDragInProgress && newWin.isPotentialDragTarget()) {
            DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
                    touchX, touchY, null, desc, null, false);
            try {
                newWin.mClient.dispatchDragEvent(event);
                // track each window that we've notified that the drag is starting
                mNotifiedWindows.add(newWin);
            } catch (RemoteException e) {
                Slog.w(WindowManagerService.TAG, "Unable to drag-start window " + newWin);
            } finally {
                // if the callee was local, the dispatch has already recycled the event
                if (Process.myPid() != newWin.mSession.mPid) {
                    event.recycle();
                }
            }
        }
    
voidunregister()

        if (WindowManagerService.DEBUG_DRAG) Slog.d(WindowManagerService.TAG, "unregistering drag input channel");
        if (mClientChannel == null) {
            Slog.e(WindowManagerService.TAG, "Unregister of nonexistent drag input channel");
        } else {
            mService.mInputManager.unregisterInputChannel(mServerChannel);
            mInputEventReceiver.dispose();
            mInputEventReceiver = null;
            mClientChannel.dispose();
            mServerChannel.dispose();
            mClientChannel = null;
            mServerChannel = null;

            mDragWindowHandle = null;
            mDragApplicationHandle = null;

            // Resume rotations after a drag.
            if (WindowManagerService.DEBUG_ORIENTATION) {
                Slog.d(WindowManagerService.TAG, "Resuming rotation after drag");
            }
            mService.resumeRotationLocked();
        }