Loading services/core/java/com/android/server/wm/DragDropController.java 0 → 100644 +306 −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.graphics.PixelFormat.TRANSLUCENT; import static android.view.SurfaceControl.HIDDEN; 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.content.ClipData; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Slog; import android.view.Display; import android.view.IWindow; import android.view.Surface; import android.view.Surface.OutOfResourcesException; 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. */ class DragDropController { private static final float DRAG_SHADOW_ALPHA_TRANSPARENT = .7071f; private static final long DRAG_TIMEOUT_MS = 5000; IBinder prepareDrag(WindowManagerService service, 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 + " flags=" + Integer.toHexString(flags) + " win=" + window + " asbinder=" + window.asBinder()); } IBinder token = null; synchronized (service.mWindowMap) { try { if (service.mDragState == null) { // TODO(multi-display): support other displays final DisplayContent displayContent = service.getDefaultDisplayContentLocked(); final Display display = displayContent.getDisplay(); SurfaceControl surface = new SurfaceControl(session, "drag surface", width, height, TRANSLUCENT, HIDDEN); 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(); token = new Binder(); service.mDragState = new DragState(service, token, surface, flags, winBinder); service.mDragState.mPid = callerPid; service.mDragState.mUid = callerUid; service.mDragState.mOriginalAlpha = alpha; token = service.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); } else { Slog.w(TAG_WM, "Drag already in progress"); } } catch (OutOfResourcesException e) { Slog.e(TAG_WM, "Can't allocate drag surface w=" + width + " h=" + height, e); if (service.mDragState != null) { service.mDragState.reset(); service.mDragState = null; } } } return token; } boolean performDrag(WindowManagerService service, 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) { if (service.mDragState == null) { Slog.w(TAG_WM, "No drag prepared"); throw new IllegalStateException("performDrag() without prepareDrag()"); } if (dragToken != service.mDragState.mToken) { Slog.w(TAG_WM, "Performing mismatched drag"); throw new IllegalStateException("performDrag() does not match prepareDrag()"); } final WindowState callingWin = service.windowForClientLocked(null, window, false); if (callingWin == null) { Slog.w(TAG_WM, "Bad requesting window " + window); return false; // !!! TODO: throw here? } // !!! TODO: if input is not still focused on the initiating window, fail // 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()); // !!! 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 // the actual drag event dispatch stuff in the dragstate final DisplayContent displayContent = callingWin.getDisplayContent(); if (displayContent == null) { return false; } Display display = displayContent.getDisplay(); service.mDragState.register(display); if (!service.mInputManager.transferTouchFocus(callingWin.mInputChannel, service.mDragState.getInputChannel())) { Slog.e(TAG_WM, "Unable to transfer touch focus"); service.mDragState.unregister(); service.mDragState.reset(); service.mDragState = null; return false; } service.mDragState.mDisplayContent = displayContent; service.mDragState.mData = data; service.mDragState.broadcastDragStartedLw(touchX, touchY); service.mDragState.overridePointerIconLw(touchSource); // remember the thumb offsets for later service.mDragState.mThumbOffsetX = thumbCenterX; service.mDragState.mThumbOffsetY = thumbCenterY; // Make the surface visible at the proper location final SurfaceControl surfaceControl = service.mDragState.mSurfaceControl; if (SHOW_LIGHT_TRANSACTIONS) Slog.i( TAG_WM, ">>> OPEN TRANSACTION performDrag"); service.openSurfaceTransaction(); try { surfaceControl.setPosition(touchX - thumbCenterX, touchY - thumbCenterY); surfaceControl.setLayer(service.mDragState.getDragLayerLw()); surfaceControl.setLayerStack(display.getLayerStack()); surfaceControl.show(); } finally { service.closeSurfaceTransaction(); if (SHOW_LIGHT_TRANSACTIONS) Slog.i( TAG_WM, "<<< CLOSE TRANSACTION performDrag"); } service.mDragState.notifyLocationLw(touchX, touchY); } return true; // success! } void reportDropResult(WindowManagerService service, IWindow window, boolean consumed) { IBinder token = window.asBinder(); if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token); } synchronized (service.mWindowMap) { if (service.mDragState == null) { // Most likely the drop recipient ANRed and we ended the drag // out from under it. Log the issue and move on. Slog.w(TAG_WM, "Drop result given but no drag in progress"); return; } if (service.mDragState.mToken != token) { // We're in a drag, but the wrong window has responded. Slog.w(TAG_WM, "Invalid drop-result claim by " + window); throw new IllegalStateException("reportDropResult() by non-recipient"); } // 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); if (callingWin == null) { Slog.w(TAG_WM, "Bad result-reporting window " + window); return; // !!! TODO: throw here? } service.mDragState.mDragResult = consumed; service.mDragState.endDragLw(); } } void cancelDragAndDrop(WindowManagerService service, IBinder dragToken) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "cancelDragAndDrop"); } synchronized (service.mWindowMap) { if (service.mDragState == null) { Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()"); } if (service.mDragState.mToken != dragToken) { Slog.w(TAG_WM, "cancelDragAndDrop() does not match prepareDrag()"); throw new IllegalStateException( "cancelDragAndDrop() does not match prepareDrag()"); } service.mDragState.mDragResult = false; service.mDragState.cancelDragLw(); } } void dragRecipientEntered(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder()); } } void dragRecipientExited(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder()); } } void handleMessage(WindowManagerService service, Message msg) { switch (msg.what) { case H.DRAG_START_TIMEOUT: { IBinder win = (IBinder) msg.obj; if (DEBUG_DRAG) { Slog.w(TAG_WM, "Timeout starting drag by win " + win); } synchronized (service.mWindowMap) { // !!! TODO: ANR the app that has failed to start the drag in time if (service.mDragState != null) { service.mDragState.unregister(); service.mDragState.reset(); service.mDragState = null; } } break; } case H.DRAG_END_TIMEOUT: { IBinder win = (IBinder) msg.obj; if (DEBUG_DRAG) { Slog.w(TAG_WM, "Timeout ending drag to win " + win); } synchronized (service.mWindowMap) { // !!! TODO: ANR the drag-receiving app if (service.mDragState != null) { service.mDragState.mDragResult = false; service.mDragState.endDragLw(); } } break; } case H.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) { interceptor.tearDown(); } } break; } } } } services/core/java/com/android/server/wm/Session.java +38 −158 Original line number Diff line number Diff line Loading @@ -81,6 +81,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { private final Set<WindowSurfaceController> mAppOverlaySurfaces = new HashSet<>(); // Set of visible alert window surfaces connected to this session. private final Set<WindowSurfaceController> mAlertWindowSurfaces = new HashSet<>(); private final DragDropController mDragDropController; final boolean mCanAddInternalSystemWindow; final boolean mCanHideNonSystemOverlayWindows; final boolean mCanAcquireSleepToken; Loading @@ -106,6 +107,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { mCanAcquireSleepToken = service.mContext.checkCallingOrSelfPermission(DEVICE_POWER) == PERMISSION_GRANTED; mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications; mDragDropController = mService.mDragDropController; StringBuilder sb = new StringBuilder(); sb.append("Session{"); sb.append(Integer.toHexString(System.identityHashCode(this))); Loading Loading @@ -304,192 +306,70 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { /* Drag/drop */ @Override public IBinder prepareDrag(IWindow window, int flags, int width, int height, Surface outSurface) { return mService.prepareDragSurface(window, mSurfaceSession, flags, width, height, outSurface); public IBinder prepareDrag(IWindow window, int flags, int width, int height, Surface outSurface) { final int callerPid = Binder.getCallingPid(); final int callerUid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { return mDragDropController.prepareDrag( mService, mSurfaceSession, callerPid, callerUid, window, flags, width, height, outSurface); } finally { Binder.restoreCallingIdentity(ident); } } @Override public 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 (mService.mWindowMap) { if (mService.mDragState == null) { Slog.w(TAG_WM, "No drag prepared"); throw new IllegalStateException("performDrag() without prepareDrag()"); return mDragDropController.performDrag(mService, window, dragToken, touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data); } if (dragToken != mService.mDragState.mToken) { Slog.w(TAG_WM, "Performing mismatched drag"); throw new IllegalStateException("performDrag() does not match prepareDrag()"); } WindowState callingWin = mService.windowForClientLocked(null, window, false); if (callingWin == null) { Slog.w(TAG_WM, "Bad requesting window " + window); return false; // !!! TODO: throw here? } // !!! TODO: if input is not still focused on the initiating window, fail // the drag initiation (e.g. an alarm window popped up just as the application // called performDrag() mService.mH.removeMessages(H.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 // the actual drag event dispatch stuff in the dragstate final DisplayContent displayContent = callingWin.getDisplayContent(); if (displayContent == null) { return false; } Display display = displayContent.getDisplay(); mService.mDragState.register(display); if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, mService.mDragState.getInputChannel())) { Slog.e(TAG_WM, "Unable to transfer touch focus"); mService.mDragState.unregister(); mService.mDragState.reset(); mService.mDragState = null; return false; } mService.mDragState.mDisplayContent = displayContent; mService.mDragState.mData = data; mService.mDragState.broadcastDragStartedLw(touchX, touchY); mService.mDragState.overridePointerIconLw(touchSource); // remember the thumb offsets for later mService.mDragState.mThumbOffsetX = thumbCenterX; mService.mDragState.mThumbOffsetY = thumbCenterY; // Make the surface visible at the proper location final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl; if (SHOW_LIGHT_TRANSACTIONS) Slog.i( TAG_WM, ">>> OPEN TRANSACTION performDrag"); mService.openSurfaceTransaction(); @Override public void reportDropResult(IWindow window, boolean consumed) { final long ident = Binder.clearCallingIdentity(); try { surfaceControl.setPosition(touchX - thumbCenterX, touchY - thumbCenterY); surfaceControl.setLayer(mService.mDragState.getDragLayerLw()); surfaceControl.setLayerStack(display.getLayerStack()); surfaceControl.show(); mDragDropController.reportDropResult(mService, window, consumed); } finally { mService.closeSurfaceTransaction(); if (SHOW_LIGHT_TRANSACTIONS) Slog.i( TAG_WM, "<<< CLOSE TRANSACTION performDrag"); } mService.mDragState.notifyLocationLw(touchX, touchY); Binder.restoreCallingIdentity(ident); } return true; // success! } @Override public boolean startMovingTask(IWindow window, float startX, float startY) { if (DEBUG_TASK_POSITIONING) Slog.d( TAG_WM, "startMovingTask: {" + startX + "," + startY + "}"); long ident = Binder.clearCallingIdentity(); public void cancelDragAndDrop(IBinder dragToken) { final long ident = Binder.clearCallingIdentity(); try { return mService.startMovingTask(window, startX, startY); mDragDropController.cancelDragAndDrop(mService, dragToken); } finally { Binder.restoreCallingIdentity(ident); } } @Override public void reportDropResult(IWindow window, boolean consumed) { IBinder token = window.asBinder(); if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token); } synchronized (mService.mWindowMap) { long ident = Binder.clearCallingIdentity(); try { if (mService.mDragState == null) { // Most likely the drop recipient ANRed and we ended the drag // out from under it. Log the issue and move on. Slog.w(TAG_WM, "Drop result given but no drag in progress"); return; } if (mService.mDragState.mToken != token) { // We're in a drag, but the wrong window has responded. Slog.w(TAG_WM, "Invalid drop-result claim by " + window); throw new IllegalStateException("reportDropResult() by non-recipient"); } // 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. mService.mH.removeMessages(H.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? public void dragRecipientEntered(IWindow window) { mDragDropController.dragRecipientEntered(window); } mService.mDragState.mDragResult = consumed; mService.mDragState.endDragLw(); } finally { Binder.restoreCallingIdentity(ident); } } @Override public void dragRecipientExited(IWindow window) { mDragDropController.dragRecipientExited(window); } @Override public void cancelDragAndDrop(IBinder dragToken) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "cancelDragAndDrop"); } public boolean startMovingTask(IWindow window, float startX, float startY) { if (DEBUG_TASK_POSITIONING) Slog.d( TAG_WM, "startMovingTask: {" + startX + "," + startY + "}"); synchronized (mService.mWindowMap) { long ident = Binder.clearCallingIdentity(); try { if (mService.mDragState == null) { Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()"); } if (mService.mDragState.mToken != dragToken) { Slog.w(TAG_WM, "cancelDragAndDrop() does not match prepareDrag()"); throw new IllegalStateException( "cancelDragAndDrop() does not match prepareDrag()"); } mService.mDragState.mDragResult = false; mService.mDragState.cancelDragLw(); return mService.startMovingTask(window, startX, startY); } finally { Binder.restoreCallingIdentity(ident); } } } @Override public void dragRecipientEntered(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder()); } } @Override public void dragRecipientExited(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder()); } } @Override public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { Loading services/core/java/com/android/server/wm/WindowManagerService.java +6 −108 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/wm/DragDropController.java 0 → 100644 +306 −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.graphics.PixelFormat.TRANSLUCENT; import static android.view.SurfaceControl.HIDDEN; 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.content.ClipData; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Slog; import android.view.Display; import android.view.IWindow; import android.view.Surface; import android.view.Surface.OutOfResourcesException; 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. */ class DragDropController { private static final float DRAG_SHADOW_ALPHA_TRANSPARENT = .7071f; private static final long DRAG_TIMEOUT_MS = 5000; IBinder prepareDrag(WindowManagerService service, 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 + " flags=" + Integer.toHexString(flags) + " win=" + window + " asbinder=" + window.asBinder()); } IBinder token = null; synchronized (service.mWindowMap) { try { if (service.mDragState == null) { // TODO(multi-display): support other displays final DisplayContent displayContent = service.getDefaultDisplayContentLocked(); final Display display = displayContent.getDisplay(); SurfaceControl surface = new SurfaceControl(session, "drag surface", width, height, TRANSLUCENT, HIDDEN); 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(); token = new Binder(); service.mDragState = new DragState(service, token, surface, flags, winBinder); service.mDragState.mPid = callerPid; service.mDragState.mUid = callerUid; service.mDragState.mOriginalAlpha = alpha; token = service.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); } else { Slog.w(TAG_WM, "Drag already in progress"); } } catch (OutOfResourcesException e) { Slog.e(TAG_WM, "Can't allocate drag surface w=" + width + " h=" + height, e); if (service.mDragState != null) { service.mDragState.reset(); service.mDragState = null; } } } return token; } boolean performDrag(WindowManagerService service, 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) { if (service.mDragState == null) { Slog.w(TAG_WM, "No drag prepared"); throw new IllegalStateException("performDrag() without prepareDrag()"); } if (dragToken != service.mDragState.mToken) { Slog.w(TAG_WM, "Performing mismatched drag"); throw new IllegalStateException("performDrag() does not match prepareDrag()"); } final WindowState callingWin = service.windowForClientLocked(null, window, false); if (callingWin == null) { Slog.w(TAG_WM, "Bad requesting window " + window); return false; // !!! TODO: throw here? } // !!! TODO: if input is not still focused on the initiating window, fail // 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()); // !!! 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 // the actual drag event dispatch stuff in the dragstate final DisplayContent displayContent = callingWin.getDisplayContent(); if (displayContent == null) { return false; } Display display = displayContent.getDisplay(); service.mDragState.register(display); if (!service.mInputManager.transferTouchFocus(callingWin.mInputChannel, service.mDragState.getInputChannel())) { Slog.e(TAG_WM, "Unable to transfer touch focus"); service.mDragState.unregister(); service.mDragState.reset(); service.mDragState = null; return false; } service.mDragState.mDisplayContent = displayContent; service.mDragState.mData = data; service.mDragState.broadcastDragStartedLw(touchX, touchY); service.mDragState.overridePointerIconLw(touchSource); // remember the thumb offsets for later service.mDragState.mThumbOffsetX = thumbCenterX; service.mDragState.mThumbOffsetY = thumbCenterY; // Make the surface visible at the proper location final SurfaceControl surfaceControl = service.mDragState.mSurfaceControl; if (SHOW_LIGHT_TRANSACTIONS) Slog.i( TAG_WM, ">>> OPEN TRANSACTION performDrag"); service.openSurfaceTransaction(); try { surfaceControl.setPosition(touchX - thumbCenterX, touchY - thumbCenterY); surfaceControl.setLayer(service.mDragState.getDragLayerLw()); surfaceControl.setLayerStack(display.getLayerStack()); surfaceControl.show(); } finally { service.closeSurfaceTransaction(); if (SHOW_LIGHT_TRANSACTIONS) Slog.i( TAG_WM, "<<< CLOSE TRANSACTION performDrag"); } service.mDragState.notifyLocationLw(touchX, touchY); } return true; // success! } void reportDropResult(WindowManagerService service, IWindow window, boolean consumed) { IBinder token = window.asBinder(); if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token); } synchronized (service.mWindowMap) { if (service.mDragState == null) { // Most likely the drop recipient ANRed and we ended the drag // out from under it. Log the issue and move on. Slog.w(TAG_WM, "Drop result given but no drag in progress"); return; } if (service.mDragState.mToken != token) { // We're in a drag, but the wrong window has responded. Slog.w(TAG_WM, "Invalid drop-result claim by " + window); throw new IllegalStateException("reportDropResult() by non-recipient"); } // 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); if (callingWin == null) { Slog.w(TAG_WM, "Bad result-reporting window " + window); return; // !!! TODO: throw here? } service.mDragState.mDragResult = consumed; service.mDragState.endDragLw(); } } void cancelDragAndDrop(WindowManagerService service, IBinder dragToken) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "cancelDragAndDrop"); } synchronized (service.mWindowMap) { if (service.mDragState == null) { Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()"); } if (service.mDragState.mToken != dragToken) { Slog.w(TAG_WM, "cancelDragAndDrop() does not match prepareDrag()"); throw new IllegalStateException( "cancelDragAndDrop() does not match prepareDrag()"); } service.mDragState.mDragResult = false; service.mDragState.cancelDragLw(); } } void dragRecipientEntered(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder()); } } void dragRecipientExited(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder()); } } void handleMessage(WindowManagerService service, Message msg) { switch (msg.what) { case H.DRAG_START_TIMEOUT: { IBinder win = (IBinder) msg.obj; if (DEBUG_DRAG) { Slog.w(TAG_WM, "Timeout starting drag by win " + win); } synchronized (service.mWindowMap) { // !!! TODO: ANR the app that has failed to start the drag in time if (service.mDragState != null) { service.mDragState.unregister(); service.mDragState.reset(); service.mDragState = null; } } break; } case H.DRAG_END_TIMEOUT: { IBinder win = (IBinder) msg.obj; if (DEBUG_DRAG) { Slog.w(TAG_WM, "Timeout ending drag to win " + win); } synchronized (service.mWindowMap) { // !!! TODO: ANR the drag-receiving app if (service.mDragState != null) { service.mDragState.mDragResult = false; service.mDragState.endDragLw(); } } break; } case H.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) { interceptor.tearDown(); } } break; } } } }
services/core/java/com/android/server/wm/Session.java +38 −158 Original line number Diff line number Diff line Loading @@ -81,6 +81,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { private final Set<WindowSurfaceController> mAppOverlaySurfaces = new HashSet<>(); // Set of visible alert window surfaces connected to this session. private final Set<WindowSurfaceController> mAlertWindowSurfaces = new HashSet<>(); private final DragDropController mDragDropController; final boolean mCanAddInternalSystemWindow; final boolean mCanHideNonSystemOverlayWindows; final boolean mCanAcquireSleepToken; Loading @@ -106,6 +107,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { mCanAcquireSleepToken = service.mContext.checkCallingOrSelfPermission(DEVICE_POWER) == PERMISSION_GRANTED; mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications; mDragDropController = mService.mDragDropController; StringBuilder sb = new StringBuilder(); sb.append("Session{"); sb.append(Integer.toHexString(System.identityHashCode(this))); Loading Loading @@ -304,192 +306,70 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { /* Drag/drop */ @Override public IBinder prepareDrag(IWindow window, int flags, int width, int height, Surface outSurface) { return mService.prepareDragSurface(window, mSurfaceSession, flags, width, height, outSurface); public IBinder prepareDrag(IWindow window, int flags, int width, int height, Surface outSurface) { final int callerPid = Binder.getCallingPid(); final int callerUid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { return mDragDropController.prepareDrag( mService, mSurfaceSession, callerPid, callerUid, window, flags, width, height, outSurface); } finally { Binder.restoreCallingIdentity(ident); } } @Override public 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 (mService.mWindowMap) { if (mService.mDragState == null) { Slog.w(TAG_WM, "No drag prepared"); throw new IllegalStateException("performDrag() without prepareDrag()"); return mDragDropController.performDrag(mService, window, dragToken, touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data); } if (dragToken != mService.mDragState.mToken) { Slog.w(TAG_WM, "Performing mismatched drag"); throw new IllegalStateException("performDrag() does not match prepareDrag()"); } WindowState callingWin = mService.windowForClientLocked(null, window, false); if (callingWin == null) { Slog.w(TAG_WM, "Bad requesting window " + window); return false; // !!! TODO: throw here? } // !!! TODO: if input is not still focused on the initiating window, fail // the drag initiation (e.g. an alarm window popped up just as the application // called performDrag() mService.mH.removeMessages(H.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 // the actual drag event dispatch stuff in the dragstate final DisplayContent displayContent = callingWin.getDisplayContent(); if (displayContent == null) { return false; } Display display = displayContent.getDisplay(); mService.mDragState.register(display); if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel, mService.mDragState.getInputChannel())) { Slog.e(TAG_WM, "Unable to transfer touch focus"); mService.mDragState.unregister(); mService.mDragState.reset(); mService.mDragState = null; return false; } mService.mDragState.mDisplayContent = displayContent; mService.mDragState.mData = data; mService.mDragState.broadcastDragStartedLw(touchX, touchY); mService.mDragState.overridePointerIconLw(touchSource); // remember the thumb offsets for later mService.mDragState.mThumbOffsetX = thumbCenterX; mService.mDragState.mThumbOffsetY = thumbCenterY; // Make the surface visible at the proper location final SurfaceControl surfaceControl = mService.mDragState.mSurfaceControl; if (SHOW_LIGHT_TRANSACTIONS) Slog.i( TAG_WM, ">>> OPEN TRANSACTION performDrag"); mService.openSurfaceTransaction(); @Override public void reportDropResult(IWindow window, boolean consumed) { final long ident = Binder.clearCallingIdentity(); try { surfaceControl.setPosition(touchX - thumbCenterX, touchY - thumbCenterY); surfaceControl.setLayer(mService.mDragState.getDragLayerLw()); surfaceControl.setLayerStack(display.getLayerStack()); surfaceControl.show(); mDragDropController.reportDropResult(mService, window, consumed); } finally { mService.closeSurfaceTransaction(); if (SHOW_LIGHT_TRANSACTIONS) Slog.i( TAG_WM, "<<< CLOSE TRANSACTION performDrag"); } mService.mDragState.notifyLocationLw(touchX, touchY); Binder.restoreCallingIdentity(ident); } return true; // success! } @Override public boolean startMovingTask(IWindow window, float startX, float startY) { if (DEBUG_TASK_POSITIONING) Slog.d( TAG_WM, "startMovingTask: {" + startX + "," + startY + "}"); long ident = Binder.clearCallingIdentity(); public void cancelDragAndDrop(IBinder dragToken) { final long ident = Binder.clearCallingIdentity(); try { return mService.startMovingTask(window, startX, startY); mDragDropController.cancelDragAndDrop(mService, dragToken); } finally { Binder.restoreCallingIdentity(ident); } } @Override public void reportDropResult(IWindow window, boolean consumed) { IBinder token = window.asBinder(); if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token); } synchronized (mService.mWindowMap) { long ident = Binder.clearCallingIdentity(); try { if (mService.mDragState == null) { // Most likely the drop recipient ANRed and we ended the drag // out from under it. Log the issue and move on. Slog.w(TAG_WM, "Drop result given but no drag in progress"); return; } if (mService.mDragState.mToken != token) { // We're in a drag, but the wrong window has responded. Slog.w(TAG_WM, "Invalid drop-result claim by " + window); throw new IllegalStateException("reportDropResult() by non-recipient"); } // 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. mService.mH.removeMessages(H.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? public void dragRecipientEntered(IWindow window) { mDragDropController.dragRecipientEntered(window); } mService.mDragState.mDragResult = consumed; mService.mDragState.endDragLw(); } finally { Binder.restoreCallingIdentity(ident); } } @Override public void dragRecipientExited(IWindow window) { mDragDropController.dragRecipientExited(window); } @Override public void cancelDragAndDrop(IBinder dragToken) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "cancelDragAndDrop"); } public boolean startMovingTask(IWindow window, float startX, float startY) { if (DEBUG_TASK_POSITIONING) Slog.d( TAG_WM, "startMovingTask: {" + startX + "," + startY + "}"); synchronized (mService.mWindowMap) { long ident = Binder.clearCallingIdentity(); try { if (mService.mDragState == null) { Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()"); throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()"); } if (mService.mDragState.mToken != dragToken) { Slog.w(TAG_WM, "cancelDragAndDrop() does not match prepareDrag()"); throw new IllegalStateException( "cancelDragAndDrop() does not match prepareDrag()"); } mService.mDragState.mDragResult = false; mService.mDragState.cancelDragLw(); return mService.startMovingTask(window, startX, startY); } finally { Binder.restoreCallingIdentity(ident); } } } @Override public void dragRecipientEntered(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder()); } } @Override public void dragRecipientExited(IWindow window) { if (DEBUG_DRAG) { Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder()); } } @Override public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) { Loading
services/core/java/com/android/server/wm/WindowManagerService.java +6 −108 File changed.Preview size limit exceeded, changes collapsed. Show changes