blob: c4389667a57ead81a726432a77ce8f57cb8b4140 [file] [log] [blame]
Dianne Hackborn6e1eb762011-02-17 16:07:28 -08001/*
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
17package com.android.server.wm;
18
Daichi Hirono58e25e12017-10-25 15:48:08 +090019import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
20import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
21import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080022import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
23import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
24import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
25import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
26import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080027
Daichi Hirono4a700b12017-10-04 15:49:35 +090028import android.animation.Animator;
29import android.animation.PropertyValuesHolder;
30import android.animation.ValueAnimator;
31import android.annotation.Nullable;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080032import android.content.ClipData;
33import android.content.ClipDescription;
Craig Mautner39834192012-09-02 07:47:24 -070034import android.graphics.Point;
Garfield Tand427c622018-11-30 13:00:04 -080035import android.graphics.Rect;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080036import android.hardware.input.InputManager;
Robert Carr0bcbe642018-10-11 19:07:43 -070037import android.os.Binder;
Garfield Tand427c622018-11-30 13:00:04 -080038import android.os.Build;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080039import android.os.IBinder;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080040import android.os.Process;
41import android.os.RemoteException;
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -080042import android.os.UserHandle;
43import android.os.UserManager;
Daichi Hirono01b64502017-12-15 09:49:18 +090044import android.os.UserManagerInternal;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080045import android.util.Slog;
Craig Mautner39834192012-09-02 07:47:24 -070046import android.view.Display;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080047import android.view.DragEvent;
Garfield Tand427c622018-11-30 13:00:04 -080048import android.view.InputApplicationHandle;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080049import android.view.InputChannel;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080050import android.view.InputDevice;
Garfield Tand427c622018-11-30 13:00:04 -080051import android.view.InputWindowHandle;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080052import android.view.PointerIcon;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080053import android.view.SurfaceControl;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080054import android.view.View;
55import android.view.WindowManager;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080056import android.view.animation.DecelerateInterpolator;
57import android.view.animation.Interpolator;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080058
Daichi Hirono58e25e12017-10-25 15:48:08 +090059import com.android.internal.view.IDragAndDropPermissions;
Daichi Hirono01b64502017-12-15 09:49:18 +090060import com.android.server.LocalServices;
Vladislav Kaznacheev9149d2b2015-12-15 12:16:28 -080061
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080062import java.util.ArrayList;
63
64/**
65 * Drag/drop state
66 */
67class DragState {
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -080068 private static final long MIN_ANIMATION_DURATION_MS = 195;
69 private static final long MAX_ANIMATION_DURATION_MS = 375;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -080070
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -080071 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
Daichi Hirono4a700b12017-10-04 15:49:35 +090078 // 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
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080084 final WindowManagerService mService;
Daichi Hirono58e25e12017-10-25 15:48:08 +090085 final DragDropController mDragDropController;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080086 IBinder mToken;
Daichi Hirono4a700b12017-10-04 15:49:35 +090087 /**
88 * Do not use the variable from the out of animation thread while mAnimator is not null.
89 */
Mathias Agopian29479eb2013-02-14 14:36:04 -080090 SurfaceControl mSurfaceControl;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080091 int mFlags;
92 IBinder mLocalWin;
Vladislav Kaznacheevc7482412015-11-05 14:03:07 -080093 int mPid;
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -070094 int mUid;
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -080095 int mSourceUserId;
96 boolean mCrossProfileCopyAllowed;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080097 ClipData mData;
98 ClipDescription mDataDescription;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080099 int mTouchSource;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800100 boolean mDragResult;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800101 float mOriginalAlpha;
102 float mOriginalX, mOriginalY;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800103 float mCurrentX, mCurrentY;
104 float mThumbOffsetX, mThumbOffsetY;
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700105 InputInterceptor mInputInterceptor;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800106 WindowState mTargetWindow;
107 ArrayList<WindowState> mNotifiedWindows;
108 boolean mDragInProgress;
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900109 /**
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;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800114 DisplayContent mDisplayContent;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800115
Daichi Hirono4a700b12017-10-04 15:49:35 +0900116 @Nullable private ValueAnimator mAnimator;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800117 private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800118 private Point mDisplaySize = new Point();
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800119
Robert Carre92c80c2018-08-14 15:38:44 -0700120 // A surface used to catch input events for the drag-and-drop operation.
121 SurfaceControl mInputSurface;
122
chaviwf80c6a32019-03-15 13:31:08 -0700123 private final SurfaceControl.Transaction mTransaction;
chaviwb4fa0812019-01-18 15:49:56 -0800124
Robert Carre92c80c2018-08-14 15:38:44 -0700125 private final Rect mTmpClipRect = new Rect();
126
Garfield Tand427c622018-11-30 13:00:04 -0800127 /**
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;
chaviwb5e316c2018-12-26 15:39:15 -0800132 IBinder mTransferTouchFromToken;
Garfield Tand427c622018-11-30 13:00:04 -0800133
Daichi Hironoda0748d2017-12-13 12:48:59 +0900134 DragState(WindowManagerService service, DragDropController controller, IBinder token,
135 SurfaceControl surface, int flags, IBinder localWin) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800136 mService = service;
Daichi Hironoda0748d2017-12-13 12:48:59 +0900137 mDragDropController = controller;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800138 mToken = token;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800139 mSurfaceControl = surface;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800140 mFlags = flags;
141 mLocalWin = localWin;
142 mNotifiedWindows = new ArrayList<WindowState>();
chaviwf80c6a32019-03-15 13:31:08 -0700143 mTransaction = service.mTransactionFactory.make();
Robert Carre92c80c2018-08-14 15:38:44 -0700144 }
145
Garfield Tand427c622018-11-30 13:00:04 -0800146 boolean isClosing() {
147 return mIsClosing;
148 }
149
chaviwf80c6a32019-03-15 13:31:08 -0700150 private void hideInputSurface() {
Robert Carre92c80c2018-08-14 15:38:44 -0700151 if (mInputSurface != null) {
chaviwf80c6a32019-03-15 13:31:08 -0700152 mTransaction.hide(mInputSurface).apply();
Robert Carre92c80c2018-08-14 15:38:44 -0700153 }
154 }
155
chaviwf80c6a32019-03-15 13:31:08 -0700156 private void showInputSurface() {
Robert Carre92c80c2018-08-14 15:38:44 -0700157 if (mInputSurface == null) {
chaviwf80c6a32019-03-15 13:31:08 -0700158 mInputSurface = mService.makeSurfaceBuilder(
159 mService.mRoot.getDisplayContent(mDisplayContent.getDisplayId()).getSession())
160 .setContainerLayer()
Vishnu Naire86bd982018-11-28 13:23:17 -0800161 .setName("Drag and Drop Input Consumer").build();
Robert Carre92c80c2018-08-14 15:38:44 -0700162 }
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
chaviwf80c6a32019-03-15 13:31:08 -0700170 mTransaction.show(mInputSurface);
171 mTransaction.setInputWindowInfo(mInputSurface, h);
172 mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE);
Robert Carre92c80c2018-08-14 15:38:44 -0700173
174 mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
chaviwf80c6a32019-03-15 13:31:08 -0700175 mTransaction.setWindowCrop(mInputSurface, mTmpClipRect);
176 mTransaction.transferTouchFocus(mTransferTouchFromToken, h.token);
chaviwb5e316c2018-12-26 15:39:15 -0800177 mTransferTouchFromToken = null;
chaviwf80c6a32019-03-15 13:31:08 -0700178
179 mTransaction.apply();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800180 }
181
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900182 /**
183 * After calling this, DragDropController#onDragStateClosedLocked is invoked, which causes
184 * DragDropController#mDragState becomes null.
185 */
186 void closeLocked() {
Garfield Tand427c622018-11-30 13:00:04 -0800187 mIsClosing = true;
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900188 // Unregister the input interceptor.
189 if (mInputInterceptor != null) {
190 if (DEBUG_DRAG)
191 Slog.d(TAG_WM, "unregistering drag input channel");
192
193 // Input channel should be disposed on the thread where the input is being handled.
194 mDragDropController.sendHandlerMessage(
195 MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
196 mInputInterceptor = null;
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900197 }
198
chaviwf80c6a32019-03-15 13:31:08 -0700199 hideInputSurface();
200
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900201 // Send drag end broadcast if drag start has been sent.
202 if (mDragInProgress) {
203 final int myPid = Process.myPid();
204
205 if (DEBUG_DRAG) {
206 Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
207 }
208 for (WindowState ws : mNotifiedWindows) {
209 float x = 0;
210 float y = 0;
211 if (!mDragResult && (ws.mSession.mPid == mPid)) {
212 // Report unconsumed drop location back to the app that started the drag.
213 x = mCurrentX;
214 y = mCurrentY;
215 }
216 DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
217 x, y, null, null, null, null, mDragResult);
218 try {
219 ws.mClient.dispatchDragEvent(evt);
220 } catch (RemoteException e) {
221 Slog.w(TAG_WM, "Unable to drag-end window " + ws);
222 }
223 // if the current window is in the same process,
224 // the dispatch has already recycled the event
225 if (myPid != ws.mSession.mPid) {
226 evt.recycle();
227 }
228 }
229 mNotifiedWindows.clear();
230 mDragInProgress = false;
231 }
232
233 // Take the cursor back if it has been changed.
234 if (isFromSource(InputDevice.SOURCE_MOUSE)) {
235 mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
236 mTouchSource = 0;
237 }
238
239 // Clear the internal variables.
240 if (mSurfaceControl != null) {
chaviwb4fa0812019-01-18 15:49:56 -0800241 mTransaction.reparent(mSurfaceControl, null).apply();
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900242 mSurfaceControl = null;
243 }
244 if (mAnimator != null && !mAnimationCompleted) {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900245 Slog.wtf(TAG_WM,
246 "Unexpectedly destroying mSurfaceControl while animation is running");
247 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800248 mFlags = 0;
249 mLocalWin = null;
250 mToken = null;
251 mData = null;
252 mThumbOffsetX = mThumbOffsetY = 0;
253 mNotifiedWindows = null;
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900254
255 // Notifies the controller that the drag state is closed.
256 mDragDropController.onDragStateClosedLocked(this);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800257 }
258
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700259 class InputInterceptor {
260 InputChannel mServerChannel, mClientChannel;
261 DragInputEventReceiver mInputEventReceiver;
262 InputApplicationHandle mDragApplicationHandle;
263 InputWindowHandle mDragWindowHandle;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800264
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700265 InputInterceptor(Display display) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800266 InputChannel[] channels = InputChannel.openInputChannelPair("drag");
267 mServerChannel = channels[0];
268 mClientChannel = channels[1];
269 mService.mInputManager.registerInputChannel(mServerChannel, null);
Daichi Hirono52cb2152017-09-11 15:29:42 +0900270 mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
Daichi Hirono768012e2017-10-30 10:05:37 +0900271 mService.mH.getLooper(), mDragDropController);
Jeff Brownea426552011-07-18 16:53:48 -0700272
Robert Carr0bcbe642018-10-11 19:07:43 -0700273 mDragApplicationHandle = new InputApplicationHandle(new Binder());
Jeff Brownea426552011-07-18 16:53:48 -0700274 mDragApplicationHandle.name = "drag";
275 mDragApplicationHandle.dispatchingTimeoutNanos =
276 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
277
Robert Carre0a353c2018-08-02 16:38:04 -0700278 mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800279 display.getDisplayId());
Jeff Brownea426552011-07-18 16:53:48 -0700280 mDragWindowHandle.name = "drag";
Robert Carreadae822018-10-11 19:07:03 -0700281 mDragWindowHandle.token = mServerChannel.getToken();
Daichi Hirono58e25e12017-10-25 15:48:08 +0900282 mDragWindowHandle.layer = getDragLayerLocked();
Jeff Brownea426552011-07-18 16:53:48 -0700283 mDragWindowHandle.layoutParamsFlags = 0;
284 mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
285 mDragWindowHandle.dispatchingTimeoutNanos =
286 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
287 mDragWindowHandle.visible = true;
288 mDragWindowHandle.canReceiveKeys = false;
289 mDragWindowHandle.hasFocus = true;
290 mDragWindowHandle.hasWallpaper = false;
291 mDragWindowHandle.paused = false;
292 mDragWindowHandle.ownerPid = Process.myPid();
293 mDragWindowHandle.ownerUid = Process.myUid();
294 mDragWindowHandle.inputFeatures = 0;
295 mDragWindowHandle.scaleFactor = 1.0f;
296
297 // The drag window cannot receive new touches.
298 mDragWindowHandle.touchableRegion.setEmpty();
299
300 // The drag window covers the entire display
301 mDragWindowHandle.frameLeft = 0;
302 mDragWindowHandle.frameTop = 0;
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800303 mDragWindowHandle.frameRight = mDisplaySize.x;
304 mDragWindowHandle.frameBottom = mDisplaySize.y;
Jeff Brown01a98dd2011-09-20 15:08:29 -0700305
306 // Pause rotations before a drag.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800307 if (DEBUG_ORIENTATION) {
308 Slog.d(TAG_WM, "Pausing rotation during drag");
Jeff Brown01a98dd2011-09-20 15:08:29 -0700309 }
Riddle Hsu654a6f92018-07-13 22:59:36 +0800310 mDisplayContent.pauseRotationLocked();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800311 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800312
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700313 void tearDown() {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800314 mService.mInputManager.unregisterInputChannel(mServerChannel);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800315 mInputEventReceiver.dispose();
316 mInputEventReceiver = null;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800317 mClientChannel.dispose();
318 mServerChannel.dispose();
319 mClientChannel = null;
320 mServerChannel = null;
Jeff Browncc4f7db2011-08-30 20:34:48 -0700321
322 mDragWindowHandle = null;
323 mDragApplicationHandle = null;
Jeff Brown01a98dd2011-09-20 15:08:29 -0700324
325 // Resume rotations after a drag.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800326 if (DEBUG_ORIENTATION) {
327 Slog.d(TAG_WM, "Resuming rotation after drag");
Jeff Brown01a98dd2011-09-20 15:08:29 -0700328 }
Riddle Hsu654a6f92018-07-13 22:59:36 +0800329 mDisplayContent.resumeRotationLocked();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800330 }
331 }
332
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700333 InputChannel getInputChannel() {
334 return mInputInterceptor == null ? null : mInputInterceptor.mServerChannel;
335 }
336
337 InputWindowHandle getInputWindowHandle() {
338 return mInputInterceptor == null ? null : mInputInterceptor.mDragWindowHandle;
339 }
340
341 /**
342 * @param display The Display that the window being dragged is on.
343 */
344 void register(Display display) {
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800345 display.getRealSize(mDisplaySize);
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700346 if (DEBUG_DRAG) Slog.d(TAG_WM, "registering drag input channel");
347 if (mInputInterceptor != null) {
348 Slog.e(TAG_WM, "Duplicate register of drag input channel");
349 } else {
350 mInputInterceptor = new InputInterceptor(display);
chaviwf80c6a32019-03-15 13:31:08 -0700351 showInputSurface();
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700352 }
353 }
354
Daichi Hirono58e25e12017-10-25 15:48:08 +0900355 int getDragLayerLocked() {
Wale Ogunwale5cd907d2017-01-26 14:14:08 -0800356 return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_DRAG)
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800357 * WindowManagerService.TYPE_LAYER_MULTIPLIER
358 + WindowManagerService.TYPE_LAYER_OFFSET;
359 }
360
361 /* call out to each visible window/session informing it about the drag
362 */
Daichi Hirono58e25e12017-10-25 15:48:08 +0900363 void broadcastDragStartedLocked(final float touchX, final float touchY) {
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800364 mOriginalX = mCurrentX = touchX;
365 mOriginalY = mCurrentY = touchY;
366
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800367 // Cache a base-class instance of the clip metadata so that parceling
368 // works correctly in calling out to the apps.
369 mDataDescription = (mData != null) ? mData.getDescription() : null;
370 mNotifiedWindows.clear();
371 mDragInProgress = true;
372
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800373 mSourceUserId = UserHandle.getUserId(mUid);
374
Daichi Hirono01b64502017-12-15 09:49:18 +0900375 final UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
376 mCrossProfileCopyAllowed = !userManager.getUserRestriction(
377 mSourceUserId, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800378
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800379 if (DEBUG_DRAG) {
380 Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800381 }
382
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800383 mDisplayContent.forAllWindows(w -> {
Daichi Hirono58e25e12017-10-25 15:48:08 +0900384 sendDragStartedLocked(w, touchX, touchY, mDataDescription);
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800385 }, false /* traverseTopToBottom */ );
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800386 }
387
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800388 /* helper - send a ACTION_DRAG_STARTED event, if the
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800389 * designated window is potentially a drop recipient. There are race situations
390 * around DRAG_ENDED broadcast, so we make sure that once we've declared that
391 * the drag has ended, we never send out another DRAG_STARTED for this drag action.
392 *
393 * This method clones the 'event' parameter if it's being delivered to the same
394 * process, so it's safe for the caller to call recycle() on the event afterwards.
395 */
Daichi Hirono58e25e12017-10-25 15:48:08 +0900396 private void sendDragStartedLocked(WindowState newWin, float touchX, float touchY,
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800397 ClipDescription desc) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800398 if (mDragInProgress && isValidDropTarget(newWin)) {
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700399 DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700400 touchX, touchY, null, desc, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800401 try {
402 newWin.mClient.dispatchDragEvent(event);
403 // track each window that we've notified that the drag is starting
404 mNotifiedWindows.add(newWin);
405 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800406 Slog.w(TAG_WM, "Unable to drag-start window " + newWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800407 } finally {
408 // if the callee was local, the dispatch has already recycled the event
409 if (Process.myPid() != newWin.mSession.mPid) {
410 event.recycle();
411 }
412 }
413 }
414 }
415
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800416 private boolean isValidDropTarget(WindowState targetWin) {
417 if (targetWin == null) {
418 return false;
419 }
420 if (!targetWin.isPotentialDragTarget()) {
421 return false;
422 }
Yorke Lee0e852472016-06-15 10:03:18 -0700423 if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0 || !targetWindowSupportsGlobalDrag(targetWin)) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800424 // Drag is limited to the current window.
425 if (mLocalWin != targetWin.mClient.asBinder()) {
426 return false;
427 }
428 }
429
430 return mCrossProfileCopyAllowed ||
431 mSourceUserId == UserHandle.getUserId(targetWin.getOwningUid());
432 }
433
Yorke Lee0e852472016-06-15 10:03:18 -0700434 private boolean targetWindowSupportsGlobalDrag(WindowState targetWin) {
435 // Global drags are limited to system windows, and windows for apps that are targeting N and
436 // above.
437 return targetWin.mAppToken == null
Wale Ogunwale72919d22016-12-08 18:58:50 -0800438 || targetWin.mAppToken.mTargetSdk >= Build.VERSION_CODES.N;
Yorke Lee0e852472016-06-15 10:03:18 -0700439 }
440
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800441 /* helper - send a ACTION_DRAG_STARTED event only if the window has not
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800442 * previously been notified, i.e. it became visible after the drag operation
443 * was begun. This is a rare case.
444 */
Daichi Hirono58e25e12017-10-25 15:48:08 +0900445 void sendDragStartedIfNeededLocked(WindowState newWin) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800446 if (mDragInProgress) {
447 // If we have sent the drag-started, we needn't do so again
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800448 if (isWindowNotified(newWin)) {
449 return;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800450 }
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800451 if (DEBUG_DRAG) {
452 Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800453 }
Daichi Hirono58e25e12017-10-25 15:48:08 +0900454 sendDragStartedLocked(newWin, mCurrentX, mCurrentY, mDataDescription);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800455 }
456 }
457
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800458 private boolean isWindowNotified(WindowState newWin) {
459 for (WindowState ws : mNotifiedWindows) {
460 if (ws == newWin) {
461 return true;
462 }
463 }
464 return false;
465 }
466
Daichi Hirono58e25e12017-10-25 15:48:08 +0900467 void endDragLocked() {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900468 if (mAnimator != null) {
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800469 return;
470 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800471 if (!mDragResult) {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900472 mAnimator = createReturnAnimationLocked();
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900473 return; // Will call closeLocked() when the animation is done.
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800474 }
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900475 closeLocked();
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800476 }
477
Daichi Hirono58e25e12017-10-25 15:48:08 +0900478 void cancelDragLocked() {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900479 if (mAnimator != null) {
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800480 return;
481 }
Daichi Hirono4a700b12017-10-04 15:49:35 +0900482 if (!mDragInProgress) {
483 // This can happen if an app invokes Session#cancelDragAndDrop before
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900484 // Session#performDrag. Reset the drag state without playing the cancel animation
485 // because H.DRAG_START_TIMEOUT may be sent to WindowManagerService, which will cause
486 // DragState#reset() while playing the cancel animation.
487 closeLocked();
Daichi Hirono4a700b12017-10-04 15:49:35 +0900488 return;
489 }
490 mAnimator = createCancelAnimationLocked();
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800491 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800492
Daichi Hirono58e25e12017-10-25 15:48:08 +0900493 void notifyMoveLocked(float x, float y) {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900494 if (mAnimator != null) {
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800495 return;
496 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800497 mCurrentX = x;
498 mCurrentY = y;
499
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800500 // Move the surface to the given touch
chaviwb4fa0812019-01-18 15:49:56 -0800501 if (SHOW_LIGHT_TRANSACTIONS) {
502 Slog.i(TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
503 }
504 mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply();
505 if (SHOW_TRANSACTIONS) {
506 Slog.i(TAG_WM, " DRAG " + mSurfaceControl + ": pos=(" + (int) (x - mThumbOffsetX) + ","
507 + (int) (y - mThumbOffsetY) + ")");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800508 }
Daichi Hirono58e25e12017-10-25 15:48:08 +0900509 notifyLocationLocked(x, y);
Vladislav Kaznacheevd0ed8932016-01-15 15:37:05 -0800510 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800511
Daichi Hirono58e25e12017-10-25 15:48:08 +0900512 void notifyLocationLocked(float x, float y) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800513 // Tell the affected window
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800514 WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
Vladislav Kaznacheev598d40d2016-04-19 15:24:52 -0700515 if (touchedWin != null && !isWindowNotified(touchedWin)) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800516 // The drag point is over a window which was not notified about a drag start.
517 // Pretend it's over empty space.
518 touchedWin = null;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800519 }
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800520
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800521 try {
Vladislav Kaznacheevd0ed8932016-01-15 15:37:05 -0800522 final int myPid = Process.myPid();
523
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800524 // have we dragged over a new window?
525 if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800526 if (DEBUG_DRAG) {
527 Slog.d(TAG_WM, "sending DRAG_EXITED to " + mTargetWindow);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800528 }
529 // force DRAG_EXITED_EVENT if appropriate
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700530 DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
Vladislav Kaznacheevcc010b22016-01-21 16:24:40 -0800531 0, 0, null, null, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800532 mTargetWindow.mClient.dispatchDragEvent(evt);
533 if (myPid != mTargetWindow.mSession.mPid) {
534 evt.recycle();
535 }
536 }
537 if (touchedWin != null) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800538 if (false && DEBUG_DRAG) {
539 Slog.d(TAG_WM, "sending DRAG_LOCATION to " + touchedWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800540 }
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700541 DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700542 x, y, null, null, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800543 touchedWin.mClient.dispatchDragEvent(evt);
544 if (myPid != touchedWin.mSession.mPid) {
545 evt.recycle();
546 }
547 }
548 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800549 Slog.w(TAG_WM, "can't send drag notification to windows");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800550 }
551 mTargetWindow = touchedWin;
552 }
553
Daichi Hirono768012e2017-10-30 10:05:37 +0900554 /**
555 * Finds the drop target and tells it about the data. If the drop event is not sent to the
556 * target, invokes {@code endDragLocked} immediately.
557 */
558 void notifyDropLocked(float x, float y) {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900559 if (mAnimator != null) {
Daichi Hirono768012e2017-10-30 10:05:37 +0900560 return;
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800561 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800562 mCurrentX = x;
563 mCurrentY = y;
564
Daichi Hirono768012e2017-10-30 10:05:37 +0900565 final WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800566
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800567 if (!isWindowNotified(touchedWin)) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800568 // "drop" outside a valid window -- no recipient to apply a
569 // timeout to, and we can send the drag-ended message immediately.
570 mDragResult = false;
Daichi Hirono768012e2017-10-30 10:05:37 +0900571 endDragLocked();
572 return;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800573 }
574
Daichi Hirono768012e2017-10-30 10:05:37 +0900575 if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800576
577 final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
578
Daichi Hirono768012e2017-10-30 10:05:37 +0900579 final DragAndDropPermissionsHandler dragAndDropPermissions;
Daichi Hironoda0748d2017-12-13 12:48:59 +0900580 if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
581 && mData != null) {
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700582 dragAndDropPermissions = new DragAndDropPermissionsHandler(
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800583 mData,
584 mUid,
585 touchedWin.getOwningPackage(),
586 mFlags & DRAG_FLAGS_URI_PERMISSIONS,
587 mSourceUserId,
588 targetUserId);
Daichi Hirono768012e2017-10-30 10:05:37 +0900589 } else {
590 dragAndDropPermissions = null;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800591 }
592 if (mSourceUserId != targetUserId){
Daichi Hironoda0748d2017-12-13 12:48:59 +0900593 if (mData != null) {
594 mData.fixUris(mSourceUserId);
595 }
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800596 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800597 final int myPid = Process.myPid();
598 final IBinder token = touchedWin.mClient.asBinder();
Daichi Hirono768012e2017-10-30 10:05:37 +0900599 final DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700600 null, null, mData, dragAndDropPermissions, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800601 try {
602 touchedWin.mClient.dispatchDragEvent(evt);
603
604 // 5 second timeout for this window to respond to the drop
Daichi Hirono58e25e12017-10-25 15:48:08 +0900605 mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800606 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800607 Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
Daichi Hirono768012e2017-10-30 10:05:37 +0900608 endDragLocked();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800609 } finally {
610 if (myPid != touchedWin.mSession.mPid) {
611 evt.recycle();
612 }
613 }
614 mToken = token;
Daichi Hirono58e25e12017-10-25 15:48:08 +0900615 }
616
Daichi Hirono663e9a72017-11-10 13:51:02 +0900617 /**
618 * Returns true if it has sent DRAG_STARTED broadcast out but has not been sent DRAG_END
619 * broadcast.
620 */
621 boolean isInProgress() {
622 return mDragInProgress;
623 }
624
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700625 private static DragEvent obtainDragEvent(WindowState win, int action,
626 float x, float y, Object localState,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700627 ClipDescription description, ClipData data,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700628 IDragAndDropPermissions dragAndDropPermissions,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700629 boolean result) {
Vladislav Kaznacheev989b58a2016-02-10 12:19:33 -0800630 final float winX = win.translateToWindowX(x);
631 final float winY = win.translateToWindowY(y);
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700632 return DragEvent.obtain(action, winX, winY, localState, description, data,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700633 dragAndDropPermissions, result);
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700634 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800635
Daichi Hirono4a700b12017-10-04 15:49:35 +0900636 private ValueAnimator createReturnAnimationLocked() {
637 final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
638 PropertyValuesHolder.ofFloat(
639 ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX,
640 mOriginalX - mThumbOffsetX),
641 PropertyValuesHolder.ofFloat(
642 ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY,
643 mOriginalY - mThumbOffsetY),
644 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 1),
645 PropertyValuesHolder.ofFloat(
646 ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, mOriginalAlpha / 2));
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800647
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800648 final float translateX = mOriginalX - mCurrentX;
649 final float translateY = mOriginalY - mCurrentY;
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800650 // Adjust the duration to the travel distance.
651 final double travelDistance = Math.sqrt(translateX * translateX + translateY * translateY);
652 final double displayDiagonal =
653 Math.sqrt(mDisplaySize.x * mDisplaySize.x + mDisplaySize.y * mDisplaySize.y);
654 final long duration = MIN_ANIMATION_DURATION_MS + (long) (travelDistance / displayDiagonal
655 * (MAX_ANIMATION_DURATION_MS - MIN_ANIMATION_DURATION_MS));
Daichi Hirono4a700b12017-10-04 15:49:35 +0900656 final AnimationListener listener = new AnimationListener();
657 animator.setDuration(duration);
658 animator.setInterpolator(mCubicEaseOutInterpolator);
659 animator.addListener(listener);
660 animator.addUpdateListener(listener);
661
662 mService.mAnimationHandler.post(() -> animator.start());
663 return animator;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800664 }
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800665
Daichi Hirono4a700b12017-10-04 15:49:35 +0900666 private ValueAnimator createCancelAnimationLocked() {
667 final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
668 PropertyValuesHolder.ofFloat(
669 ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX, mCurrentX),
670 PropertyValuesHolder.ofFloat(
671 ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY, mCurrentY),
672 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 0),
673 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0));
674 final AnimationListener listener = new AnimationListener();
675 animator.setDuration(MIN_ANIMATION_DURATION_MS);
676 animator.setInterpolator(mCubicEaseOutInterpolator);
677 animator.addListener(listener);
678 animator.addUpdateListener(listener);
679
680 mService.mAnimationHandler.post(() -> animator.start());
681 return animator;
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800682 }
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800683
684 private boolean isFromSource(int source) {
685 return (mTouchSource & source) == source;
686 }
687
Daichi Hirono58e25e12017-10-25 15:48:08 +0900688 void overridePointerIconLocked(int touchSource) {
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800689 mTouchSource = touchSource;
690 if (isFromSource(InputDevice.SOURCE_MOUSE)) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100691 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_GRABBING);
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800692 }
693 }
Daichi Hirono4a700b12017-10-04 15:49:35 +0900694
Daichi Hirono4a700b12017-10-04 15:49:35 +0900695 private class AnimationListener
696 implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
697 @Override
698 public void onAnimationUpdate(ValueAnimator animation) {
699 try (final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
700 transaction.setPosition(
701 mSurfaceControl,
Daichi Hirono971fe912017-11-21 13:10:42 +0900702 (float) animation.getAnimatedValue(ANIMATED_PROPERTY_X),
703 (float) animation.getAnimatedValue(ANIMATED_PROPERTY_Y));
Daichi Hirono4a700b12017-10-04 15:49:35 +0900704 transaction.setAlpha(
705 mSurfaceControl,
Daichi Hirono971fe912017-11-21 13:10:42 +0900706 (float) animation.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
Daichi Hirono4a700b12017-10-04 15:49:35 +0900707 transaction.setMatrix(
708 mSurfaceControl,
Daichi Hirono971fe912017-11-21 13:10:42 +0900709 (float) animation.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
710 0, (float) animation.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
Daichi Hirono4a700b12017-10-04 15:49:35 +0900711 transaction.apply();
712 }
713 }
714
715 @Override
716 public void onAnimationStart(Animator animator) {}
717
718 @Override
719 public void onAnimationCancel(Animator animator) {}
720
721 @Override
722 public void onAnimationRepeat(Animator animator) {}
723
724 @Override
725 public void onAnimationEnd(Animator animator) {
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900726 mAnimationCompleted = true;
Daichi Hirono4a700b12017-10-04 15:49:35 +0900727 // Updating mDragState requires the WM lock so continues it on the out of
728 // AnimationThread.
Daichi Hirono58e25e12017-10-25 15:48:08 +0900729 mDragDropController.sendHandlerMessage(MSG_ANIMATION_END, null);
Daichi Hirono4a700b12017-10-04 15:49:35 +0900730 }
731 }
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800732}