• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
20 import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
21 import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
22 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
23 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
24 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
25 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
26 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
27 
28 import android.animation.Animator;
29 import android.animation.PropertyValuesHolder;
30 import android.animation.ValueAnimator;
31 import android.annotation.Nullable;
32 import android.content.ClipData;
33 import android.content.ClipDescription;
34 import android.graphics.Point;
35 import android.graphics.Rect;
36 import android.hardware.input.InputManager;
37 import android.os.Binder;
38 import android.os.Build;
39 import android.os.IBinder;
40 import android.os.Process;
41 import android.os.RemoteException;
42 import android.os.UserHandle;
43 import android.os.UserManager;
44 import android.os.UserManagerInternal;
45 import android.util.Slog;
46 import android.view.Display;
47 import android.view.DragEvent;
48 import android.view.InputApplicationHandle;
49 import android.view.InputChannel;
50 import android.view.InputDevice;
51 import android.view.InputWindowHandle;
52 import android.view.PointerIcon;
53 import android.view.SurfaceControl;
54 import android.view.View;
55 import android.view.WindowManager;
56 import android.view.animation.DecelerateInterpolator;
57 import android.view.animation.Interpolator;
58 
59 import com.android.internal.view.IDragAndDropPermissions;
60 import com.android.server.LocalServices;
61 
62 import java.util.ArrayList;
63 
64 /**
65  * Drag/drop state
66  */
67 class DragState {
68     private static final long MIN_ANIMATION_DURATION_MS = 195;
69     private static final long MAX_ANIMATION_DURATION_MS = 375;
70 
71     private static final int DRAG_FLAGS_URI_ACCESS = View.DRAG_FLAG_GLOBAL_URI_READ |
72             View.DRAG_FLAG_GLOBAL_URI_WRITE;
73 
74     private static final int DRAG_FLAGS_URI_PERMISSIONS = DRAG_FLAGS_URI_ACCESS |
75             View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION |
76             View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
77 
78     // Property names for animations
79     private static final String ANIMATED_PROPERTY_X = "x";
80     private static final String ANIMATED_PROPERTY_Y = "y";
81     private static final String ANIMATED_PROPERTY_ALPHA = "alpha";
82     private static final String ANIMATED_PROPERTY_SCALE = "scale";
83 
84     final WindowManagerService mService;
85     final DragDropController mDragDropController;
86     IBinder mToken;
87     /**
88      * Do not use the variable from the out of animation thread while mAnimator is not null.
89      */
90     SurfaceControl mSurfaceControl;
91     int mFlags;
92     IBinder mLocalWin;
93     int mPid;
94     int mUid;
95     int mSourceUserId;
96     boolean mCrossProfileCopyAllowed;
97     ClipData mData;
98     ClipDescription mDataDescription;
99     int mTouchSource;
100     boolean mDragResult;
101     float mOriginalAlpha;
102     float mOriginalX, mOriginalY;
103     float mCurrentX, mCurrentY;
104     float mThumbOffsetX, mThumbOffsetY;
105     InputInterceptor mInputInterceptor;
106     WindowState mTargetWindow;
107     ArrayList<WindowState> mNotifiedWindows;
108     boolean mDragInProgress;
109     /**
110      * Whether if animation is completed. Needs to be volatile to update from the animation thread
111      * without having a WM lock.
112      */
113     volatile boolean mAnimationCompleted = false;
114     DisplayContent mDisplayContent;
115 
116     @Nullable private ValueAnimator mAnimator;
117     private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
118     private Point mDisplaySize = new Point();
119 
120     // A surface used to catch input events for the drag-and-drop operation.
121     SurfaceControl mInputSurface;
122 
123     private final SurfaceControl.Transaction mTransaction;
124 
125     private final Rect mTmpClipRect = new Rect();
126 
127     /**
128      * Whether we are finishing this drag and drop. This starts with {@code false}, and is set to
129      * {@code true} when {@link #closeLocked()} is called.
130      */
131     private boolean mIsClosing;
132     IBinder mTransferTouchFromToken;
133 
DragState(WindowManagerService service, DragDropController controller, IBinder token, SurfaceControl surface, int flags, IBinder localWin)134     DragState(WindowManagerService service, DragDropController controller, IBinder token,
135             SurfaceControl surface, int flags, IBinder localWin) {
136         mService = service;
137         mDragDropController = controller;
138         mToken = token;
139         mSurfaceControl = surface;
140         mFlags = flags;
141         mLocalWin = localWin;
142         mNotifiedWindows = new ArrayList<WindowState>();
143         mTransaction = service.mTransactionFactory.make();
144     }
145 
isClosing()146     boolean isClosing() {
147         return mIsClosing;
148     }
149 
hideInputSurface()150     private void hideInputSurface() {
151         if (mInputSurface != null) {
152             mTransaction.hide(mInputSurface).apply();
153         }
154     }
155 
showInputSurface()156     private void showInputSurface() {
157         if (mInputSurface == null) {
158             mInputSurface = mService.makeSurfaceBuilder(
159                     mService.mRoot.getDisplayContent(mDisplayContent.getDisplayId()).getSession())
160                     .setContainerLayer()
161                     .setName("Drag and Drop Input Consumer").build();
162         }
163         final InputWindowHandle h = getInputWindowHandle();
164         if (h == null) {
165             Slog.w(TAG_WM, "Drag is in progress but there is no "
166                     + "drag window handle.");
167             return;
168         }
169 
170         mTransaction.show(mInputSurface);
171         mTransaction.setInputWindowInfo(mInputSurface, h);
172         mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE);
173 
174         mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
175         mTransaction.setWindowCrop(mInputSurface, mTmpClipRect);
176         mTransaction.transferTouchFocus(mTransferTouchFromToken, h.token);
177         mTransferTouchFromToken = null;
178 
179         // syncInputWindows here to ensure the input channel isn't removed before the transfer.
180         mTransaction.syncInputWindows();
181         mTransaction.apply();
182     }
183 
184     /**
185      * After calling this, DragDropController#onDragStateClosedLocked is invoked, which causes
186      * DragDropController#mDragState becomes null.
187      */
closeLocked()188     void closeLocked() {
189         mIsClosing = true;
190         // Unregister the input interceptor.
191         if (mInputInterceptor != null) {
192             if (DEBUG_DRAG)
193                 Slog.d(TAG_WM, "unregistering drag input channel");
194 
195             // Input channel should be disposed on the thread where the input is being handled.
196             mDragDropController.sendHandlerMessage(
197                     MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
198             mInputInterceptor = null;
199         }
200 
201         hideInputSurface();
202 
203         // Send drag end broadcast if drag start has been sent.
204         if (mDragInProgress) {
205             final int myPid = Process.myPid();
206 
207             if (DEBUG_DRAG) {
208                 Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
209             }
210             for (WindowState ws : mNotifiedWindows) {
211                 float x = 0;
212                 float y = 0;
213                 if (!mDragResult && (ws.mSession.mPid == mPid)) {
214                     // Report unconsumed drop location back to the app that started the drag.
215                     x = mCurrentX;
216                     y = mCurrentY;
217                 }
218                 DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
219                         x, y, null, null, null, null, mDragResult);
220                 try {
221                     ws.mClient.dispatchDragEvent(evt);
222                 } catch (RemoteException e) {
223                     Slog.w(TAG_WM, "Unable to drag-end window " + ws);
224                 }
225                 // if the current window is in the same process,
226                 // the dispatch has already recycled the event
227                 if (myPid != ws.mSession.mPid) {
228                     evt.recycle();
229                 }
230             }
231             mNotifiedWindows.clear();
232             mDragInProgress = false;
233         }
234 
235         // Take the cursor back if it has been changed.
236         if (isFromSource(InputDevice.SOURCE_MOUSE)) {
237             mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
238             mTouchSource = 0;
239         }
240 
241         // Clear the internal variables.
242         if (mSurfaceControl != null) {
243             mTransaction.reparent(mSurfaceControl, null).apply();
244             mSurfaceControl = null;
245         }
246         if (mAnimator != null && !mAnimationCompleted) {
247             Slog.wtf(TAG_WM,
248                     "Unexpectedly destroying mSurfaceControl while animation is running");
249         }
250         mFlags = 0;
251         mLocalWin = null;
252         mToken = null;
253         mData = null;
254         mThumbOffsetX = mThumbOffsetY = 0;
255         mNotifiedWindows = null;
256 
257         // Notifies the controller that the drag state is closed.
258         mDragDropController.onDragStateClosedLocked(this);
259     }
260 
261     class InputInterceptor {
262         InputChannel mServerChannel, mClientChannel;
263         DragInputEventReceiver mInputEventReceiver;
264         InputApplicationHandle mDragApplicationHandle;
265         InputWindowHandle mDragWindowHandle;
266 
InputInterceptor(Display display)267         InputInterceptor(Display display) {
268             InputChannel[] channels = InputChannel.openInputChannelPair("drag");
269             mServerChannel = channels[0];
270             mClientChannel = channels[1];
271             mService.mInputManager.registerInputChannel(mServerChannel, null);
272             mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
273                     mService.mH.getLooper(), mDragDropController);
274 
275             mDragApplicationHandle = new InputApplicationHandle(new Binder());
276             mDragApplicationHandle.name = "drag";
277             mDragApplicationHandle.dispatchingTimeoutNanos =
278                     WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
279 
280             mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
281                     display.getDisplayId());
282             mDragWindowHandle.name = "drag";
283             mDragWindowHandle.token = mServerChannel.getToken();
284             mDragWindowHandle.layer = getDragLayerLocked();
285             mDragWindowHandle.layoutParamsFlags = 0;
286             mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
287             mDragWindowHandle.dispatchingTimeoutNanos =
288                     WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
289             mDragWindowHandle.visible = true;
290             mDragWindowHandle.canReceiveKeys = false;
291             mDragWindowHandle.hasFocus = true;
292             mDragWindowHandle.hasWallpaper = false;
293             mDragWindowHandle.paused = false;
294             mDragWindowHandle.ownerPid = Process.myPid();
295             mDragWindowHandle.ownerUid = Process.myUid();
296             mDragWindowHandle.inputFeatures = 0;
297             mDragWindowHandle.scaleFactor = 1.0f;
298 
299             // The drag window cannot receive new touches.
300             mDragWindowHandle.touchableRegion.setEmpty();
301 
302             // The drag window covers the entire display
303             mDragWindowHandle.frameLeft = 0;
304             mDragWindowHandle.frameTop = 0;
305             mDragWindowHandle.frameRight = mDisplaySize.x;
306             mDragWindowHandle.frameBottom = mDisplaySize.y;
307 
308             // Pause rotations before a drag.
309             if (DEBUG_ORIENTATION) {
310                 Slog.d(TAG_WM, "Pausing rotation during drag");
311             }
312             mDisplayContent.pauseRotationLocked();
313         }
314 
tearDown()315         void tearDown() {
316             mService.mInputManager.unregisterInputChannel(mServerChannel);
317             mInputEventReceiver.dispose();
318             mInputEventReceiver = null;
319             mClientChannel.dispose();
320             mServerChannel.dispose();
321             mClientChannel = null;
322             mServerChannel = null;
323 
324             mDragWindowHandle = null;
325             mDragApplicationHandle = null;
326 
327             // Resume rotations after a drag.
328             if (DEBUG_ORIENTATION) {
329                 Slog.d(TAG_WM, "Resuming rotation after drag");
330             }
331             mDisplayContent.resumeRotationLocked();
332         }
333     }
334 
getInputChannel()335     InputChannel getInputChannel() {
336         return mInputInterceptor == null ? null : mInputInterceptor.mServerChannel;
337     }
338 
getInputWindowHandle()339     InputWindowHandle getInputWindowHandle() {
340         return mInputInterceptor == null ? null : mInputInterceptor.mDragWindowHandle;
341     }
342 
343     /**
344      * @param display The Display that the window being dragged is on.
345      */
register(Display display)346     void register(Display display) {
347         display.getRealSize(mDisplaySize);
348         if (DEBUG_DRAG) Slog.d(TAG_WM, "registering drag input channel");
349         if (mInputInterceptor != null) {
350             Slog.e(TAG_WM, "Duplicate register of drag input channel");
351         } else {
352             mInputInterceptor = new InputInterceptor(display);
353             showInputSurface();
354         }
355     }
356 
getDragLayerLocked()357     int getDragLayerLocked() {
358         return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_DRAG)
359                 * WindowManagerService.TYPE_LAYER_MULTIPLIER
360                 + WindowManagerService.TYPE_LAYER_OFFSET;
361     }
362 
363     /* call out to each visible window/session informing it about the drag
364      */
broadcastDragStartedLocked(final float touchX, final float touchY)365     void broadcastDragStartedLocked(final float touchX, final float touchY) {
366         mOriginalX = mCurrentX = touchX;
367         mOriginalY = mCurrentY = touchY;
368 
369         // Cache a base-class instance of the clip metadata so that parceling
370         // works correctly in calling out to the apps.
371         mDataDescription = (mData != null) ? mData.getDescription() : null;
372         mNotifiedWindows.clear();
373         mDragInProgress = true;
374 
375         mSourceUserId = UserHandle.getUserId(mUid);
376 
377         final UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
378         mCrossProfileCopyAllowed = !userManager.getUserRestriction(
379                 mSourceUserId, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
380 
381         if (DEBUG_DRAG) {
382             Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
383         }
384 
385         mDisplayContent.forAllWindows(w -> {
386             sendDragStartedLocked(w, touchX, touchY, mDataDescription);
387         }, false /* traverseTopToBottom */ );
388     }
389 
390     /* helper - send a ACTION_DRAG_STARTED event, if the
391      * designated window is potentially a drop recipient.  There are race situations
392      * around DRAG_ENDED broadcast, so we make sure that once we've declared that
393      * the drag has ended, we never send out another DRAG_STARTED for this drag action.
394      *
395      * This method clones the 'event' parameter if it's being delivered to the same
396      * process, so it's safe for the caller to call recycle() on the event afterwards.
397      */
sendDragStartedLocked(WindowState newWin, float touchX, float touchY, ClipDescription desc)398     private void sendDragStartedLocked(WindowState newWin, float touchX, float touchY,
399             ClipDescription desc) {
400         if (mDragInProgress && isValidDropTarget(newWin)) {
401             DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
402                     touchX, touchY, null, desc, null, null, false);
403             try {
404                 newWin.mClient.dispatchDragEvent(event);
405                 // track each window that we've notified that the drag is starting
406                 mNotifiedWindows.add(newWin);
407             } catch (RemoteException e) {
408                 Slog.w(TAG_WM, "Unable to drag-start window " + newWin);
409             } finally {
410                 // if the callee was local, the dispatch has already recycled the event
411                 if (Process.myPid() != newWin.mSession.mPid) {
412                     event.recycle();
413                 }
414             }
415         }
416     }
417 
isValidDropTarget(WindowState targetWin)418     private boolean isValidDropTarget(WindowState targetWin) {
419         if (targetWin == null) {
420             return false;
421         }
422         if (!targetWin.isPotentialDragTarget()) {
423             return false;
424         }
425         if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0 || !targetWindowSupportsGlobalDrag(targetWin)) {
426             // Drag is limited to the current window.
427             if (mLocalWin != targetWin.mClient.asBinder()) {
428                 return false;
429             }
430         }
431 
432         return mCrossProfileCopyAllowed ||
433                 mSourceUserId == UserHandle.getUserId(targetWin.getOwningUid());
434     }
435 
targetWindowSupportsGlobalDrag(WindowState targetWin)436     private boolean targetWindowSupportsGlobalDrag(WindowState targetWin) {
437         // Global drags are limited to system windows, and windows for apps that are targeting N and
438         // above.
439         return targetWin.mAppToken == null
440                 || targetWin.mAppToken.mTargetSdk >= Build.VERSION_CODES.N;
441     }
442 
443     /* helper - send a ACTION_DRAG_STARTED event only if the window has not
444      * previously been notified, i.e. it became visible after the drag operation
445      * was begun.  This is a rare case.
446      */
sendDragStartedIfNeededLocked(WindowState newWin)447     void sendDragStartedIfNeededLocked(WindowState newWin) {
448         if (mDragInProgress) {
449             // If we have sent the drag-started, we needn't do so again
450             if (isWindowNotified(newWin)) {
451                 return;
452             }
453             if (DEBUG_DRAG) {
454                 Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
455             }
456             sendDragStartedLocked(newWin, mCurrentX, mCurrentY, mDataDescription);
457         }
458     }
459 
isWindowNotified(WindowState newWin)460     private boolean isWindowNotified(WindowState newWin) {
461         for (WindowState ws : mNotifiedWindows) {
462             if (ws == newWin) {
463                 return true;
464             }
465         }
466         return false;
467     }
468 
endDragLocked()469     void endDragLocked() {
470         if (mAnimator != null) {
471             return;
472         }
473         if (!mDragResult) {
474             mAnimator = createReturnAnimationLocked();
475             return;  // Will call closeLocked() when the animation is done.
476         }
477         closeLocked();
478     }
479 
cancelDragLocked(boolean skipAnimation)480     void cancelDragLocked(boolean skipAnimation) {
481         if (mAnimator != null) {
482             return;
483         }
484         if (!mDragInProgress || skipAnimation) {
485             // mDragInProgress is false if an app invokes Session#cancelDragAndDrop before
486             // Session#performDrag. Reset the drag state without playing the cancel animation
487             // because H.DRAG_START_TIMEOUT may be sent to WindowManagerService, which will cause
488             // DragState#reset() while playing the cancel animation.
489             // skipAnimation is true when a caller requests to skip the drag cancel animation.
490             closeLocked();
491             return;
492         }
493         mAnimator = createCancelAnimationLocked();
494     }
495 
notifyMoveLocked(float x, float y)496     void notifyMoveLocked(float x, float y) {
497         if (mAnimator != null) {
498             return;
499         }
500         mCurrentX = x;
501         mCurrentY = y;
502 
503         // Move the surface to the given touch
504         if (SHOW_LIGHT_TRANSACTIONS) {
505             Slog.i(TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
506         }
507         mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply();
508         if (SHOW_TRANSACTIONS) {
509             Slog.i(TAG_WM, "  DRAG " + mSurfaceControl + ": pos=(" + (int) (x - mThumbOffsetX) + ","
510                     + (int) (y - mThumbOffsetY) + ")");
511         }
512         notifyLocationLocked(x, y);
513     }
514 
notifyLocationLocked(float x, float y)515     void notifyLocationLocked(float x, float y) {
516         // Tell the affected window
517         WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
518         if (touchedWin != null && !isWindowNotified(touchedWin)) {
519             // The drag point is over a window which was not notified about a drag start.
520             // Pretend it's over empty space.
521             touchedWin = null;
522         }
523 
524         try {
525             final int myPid = Process.myPid();
526 
527             // have we dragged over a new window?
528             if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
529                 if (DEBUG_DRAG) {
530                     Slog.d(TAG_WM, "sending DRAG_EXITED to " + mTargetWindow);
531                 }
532                 // force DRAG_EXITED_EVENT if appropriate
533                 DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
534                         0, 0, null, null, null, null, false);
535                 mTargetWindow.mClient.dispatchDragEvent(evt);
536                 if (myPid != mTargetWindow.mSession.mPid) {
537                     evt.recycle();
538                 }
539             }
540             if (touchedWin != null) {
541                 if (false && DEBUG_DRAG) {
542                     Slog.d(TAG_WM, "sending DRAG_LOCATION to " + touchedWin);
543                 }
544                 DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
545                         x, y, null, null, null, null, false);
546                 touchedWin.mClient.dispatchDragEvent(evt);
547                 if (myPid != touchedWin.mSession.mPid) {
548                     evt.recycle();
549                 }
550             }
551         } catch (RemoteException e) {
552             Slog.w(TAG_WM, "can't send drag notification to windows");
553         }
554         mTargetWindow = touchedWin;
555     }
556 
557     /**
558      * Finds the drop target and tells it about the data. If the drop event is not sent to the
559      * target, invokes {@code endDragLocked} immediately.
560      */
notifyDropLocked(float x, float y)561     void notifyDropLocked(float x, float y) {
562         if (mAnimator != null) {
563             return;
564         }
565         mCurrentX = x;
566         mCurrentY = y;
567 
568         final WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
569 
570         if (!isWindowNotified(touchedWin)) {
571             // "drop" outside a valid window -- no recipient to apply a
572             // timeout to, and we can send the drag-ended message immediately.
573             mDragResult = false;
574             endDragLocked();
575             return;
576         }
577 
578         if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
579 
580         final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
581 
582         final DragAndDropPermissionsHandler dragAndDropPermissions;
583         if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
584                 && mData != null) {
585             dragAndDropPermissions = new DragAndDropPermissionsHandler(
586                     mData,
587                     mUid,
588                     touchedWin.getOwningPackage(),
589                     mFlags & DRAG_FLAGS_URI_PERMISSIONS,
590                     mSourceUserId,
591                     targetUserId);
592         } else {
593             dragAndDropPermissions = null;
594         }
595         if (mSourceUserId != targetUserId){
596             if (mData != null) {
597                 mData.fixUris(mSourceUserId);
598             }
599         }
600         final int myPid = Process.myPid();
601         final IBinder token = touchedWin.mClient.asBinder();
602         final DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
603                 null, null, mData, dragAndDropPermissions, false);
604         try {
605             touchedWin.mClient.dispatchDragEvent(evt);
606 
607             // 5 second timeout for this window to respond to the drop
608             mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token);
609         } catch (RemoteException e) {
610             Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
611             endDragLocked();
612         } finally {
613             if (myPid != touchedWin.mSession.mPid) {
614                 evt.recycle();
615             }
616         }
617         mToken = token;
618     }
619 
620     /**
621      * Returns true if it has sent DRAG_STARTED broadcast out but has not been sent DRAG_END
622      * broadcast.
623      */
isInProgress()624     boolean isInProgress() {
625         return mDragInProgress;
626     }
627 
obtainDragEvent(WindowState win, int action, float x, float y, Object localState, ClipDescription description, ClipData data, IDragAndDropPermissions dragAndDropPermissions, boolean result)628     private static DragEvent obtainDragEvent(WindowState win, int action,
629             float x, float y, Object localState,
630             ClipDescription description, ClipData data,
631             IDragAndDropPermissions dragAndDropPermissions,
632             boolean result) {
633         final float winX = win.translateToWindowX(x);
634         final float winY = win.translateToWindowY(y);
635         return DragEvent.obtain(action, winX, winY, localState, description, data,
636                 dragAndDropPermissions, result);
637     }
638 
createReturnAnimationLocked()639     private ValueAnimator createReturnAnimationLocked() {
640         final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
641                 PropertyValuesHolder.ofFloat(
642                         ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX,
643                         mOriginalX - mThumbOffsetX),
644                 PropertyValuesHolder.ofFloat(
645                         ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY,
646                         mOriginalY - mThumbOffsetY),
647                 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 1),
648                 PropertyValuesHolder.ofFloat(
649                         ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, mOriginalAlpha / 2));
650 
651         final float translateX = mOriginalX - mCurrentX;
652         final float translateY = mOriginalY - mCurrentY;
653         // Adjust the duration to the travel distance.
654         final double travelDistance = Math.sqrt(translateX * translateX + translateY * translateY);
655         final double displayDiagonal =
656                 Math.sqrt(mDisplaySize.x * mDisplaySize.x + mDisplaySize.y * mDisplaySize.y);
657         final long duration = MIN_ANIMATION_DURATION_MS + (long) (travelDistance / displayDiagonal
658                 * (MAX_ANIMATION_DURATION_MS - MIN_ANIMATION_DURATION_MS));
659         final AnimationListener listener = new AnimationListener();
660         animator.setDuration(duration);
661         animator.setInterpolator(mCubicEaseOutInterpolator);
662         animator.addListener(listener);
663         animator.addUpdateListener(listener);
664 
665         mService.mAnimationHandler.post(() -> animator.start());
666         return animator;
667     }
668 
createCancelAnimationLocked()669     private ValueAnimator createCancelAnimationLocked() {
670         final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
671                 PropertyValuesHolder.ofFloat(
672                         ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX, mCurrentX),
673                 PropertyValuesHolder.ofFloat(
674                         ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY, mCurrentY),
675                 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 0),
676                 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0));
677         final AnimationListener listener = new AnimationListener();
678         animator.setDuration(MIN_ANIMATION_DURATION_MS);
679         animator.setInterpolator(mCubicEaseOutInterpolator);
680         animator.addListener(listener);
681         animator.addUpdateListener(listener);
682 
683         mService.mAnimationHandler.post(() -> animator.start());
684         return animator;
685     }
686 
isFromSource(int source)687     private boolean isFromSource(int source) {
688         return (mTouchSource & source) == source;
689     }
690 
overridePointerIconLocked(int touchSource)691     void overridePointerIconLocked(int touchSource) {
692         mTouchSource = touchSource;
693         if (isFromSource(InputDevice.SOURCE_MOUSE)) {
694             InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_GRABBING);
695         }
696     }
697 
698     private class AnimationListener
699             implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
700         @Override
onAnimationUpdate(ValueAnimator animation)701         public void onAnimationUpdate(ValueAnimator animation) {
702             try (final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
703                 transaction.setPosition(
704                         mSurfaceControl,
705                         (float) animation.getAnimatedValue(ANIMATED_PROPERTY_X),
706                         (float) animation.getAnimatedValue(ANIMATED_PROPERTY_Y));
707                 transaction.setAlpha(
708                         mSurfaceControl,
709                         (float) animation.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
710                 transaction.setMatrix(
711                         mSurfaceControl,
712                         (float) animation.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
713                         0, (float) animation.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
714                 transaction.apply();
715             }
716         }
717 
718         @Override
onAnimationStart(Animator animator)719         public void onAnimationStart(Animator animator) {}
720 
721         @Override
onAnimationCancel(Animator animator)722         public void onAnimationCancel(Animator animator) {}
723 
724         @Override
onAnimationRepeat(Animator animator)725         public void onAnimationRepeat(Animator animator) {}
726 
727         @Override
onAnimationEnd(Animator animator)728         public void onAnimationEnd(Animator animator) {
729             mAnimationCompleted = true;
730             // Updating mDragState requires the WM lock so continues it on the out of
731             // AnimationThread.
732             mDragDropController.sendHandlerMessage(MSG_ANIMATION_END, null);
733         }
734     }
735 }
736