blob: e81d366bd85aad4837e4770c62caf1a94abd833c [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;
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -080034import android.content.Context;
Craig Mautner39834192012-09-02 07:47:24 -070035import android.graphics.Point;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080036import android.hardware.input.InputManager;
Yorke Lee0e852472016-06-15 10:03:18 -070037import android.os.Build;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080038import android.os.IBinder;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080039import android.os.Process;
40import android.os.RemoteException;
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -080041import android.os.ServiceManager;
42import android.os.UserHandle;
43import android.os.UserManager;
44import android.os.IUserManager;
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;
48import android.view.InputChannel;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080049import android.view.InputDevice;
50import android.view.PointerIcon;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080051import android.view.SurfaceControl;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080052import android.view.View;
53import android.view.WindowManager;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080054import android.view.animation.DecelerateInterpolator;
55import android.view.animation.Interpolator;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080056
Daichi Hirono58e25e12017-10-25 15:48:08 +090057import com.android.internal.view.IDragAndDropPermissions;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080058import com.android.server.input.InputApplicationHandle;
59import com.android.server.input.InputWindowHandle;
Vladislav Kaznacheev9149d2b2015-12-15 12:16:28 -080060
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080061import java.util.ArrayList;
62
63/**
64 * Drag/drop state
65 */
66class DragState {
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -080067 private static final long MIN_ANIMATION_DURATION_MS = 195;
68 private static final long MAX_ANIMATION_DURATION_MS = 375;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -080069
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -080070 private static final int DRAG_FLAGS_URI_ACCESS = View.DRAG_FLAG_GLOBAL_URI_READ |
71 View.DRAG_FLAG_GLOBAL_URI_WRITE;
72
73 private static final int DRAG_FLAGS_URI_PERMISSIONS = DRAG_FLAGS_URI_ACCESS |
74 View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION |
75 View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
76
Daichi Hirono4a700b12017-10-04 15:49:35 +090077 // Property names for animations
78 private static final String ANIMATED_PROPERTY_X = "x";
79 private static final String ANIMATED_PROPERTY_Y = "y";
80 private static final String ANIMATED_PROPERTY_ALPHA = "alpha";
81 private static final String ANIMATED_PROPERTY_SCALE = "scale";
82
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080083 final WindowManagerService mService;
Daichi Hirono58e25e12017-10-25 15:48:08 +090084 final DragDropController mDragDropController;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080085 IBinder mToken;
Daichi Hirono4a700b12017-10-04 15:49:35 +090086 /**
87 * Do not use the variable from the out of animation thread while mAnimator is not null.
88 */
Mathias Agopian29479eb2013-02-14 14:36:04 -080089 SurfaceControl mSurfaceControl;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080090 int mFlags;
91 IBinder mLocalWin;
Vladislav Kaznacheevc7482412015-11-05 14:03:07 -080092 int mPid;
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -070093 int mUid;
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -080094 int mSourceUserId;
95 boolean mCrossProfileCopyAllowed;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080096 ClipData mData;
97 ClipDescription mDataDescription;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080098 int mTouchSource;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080099 boolean mDragResult;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800100 float mOriginalAlpha;
101 float mOriginalX, mOriginalY;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800102 float mCurrentX, mCurrentY;
103 float mThumbOffsetX, mThumbOffsetY;
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700104 InputInterceptor mInputInterceptor;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800105 WindowState mTargetWindow;
106 ArrayList<WindowState> mNotifiedWindows;
107 boolean mDragInProgress;
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900108 /**
109 * Whether if animation is completed. Needs to be volatile to update from the animation thread
110 * without having a WM lock.
111 */
112 volatile boolean mAnimationCompleted = false;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800113 DisplayContent mDisplayContent;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800114
Daichi Hirono4a700b12017-10-04 15:49:35 +0900115 @Nullable private ValueAnimator mAnimator;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800116 private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800117 private Point mDisplaySize = new Point();
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800118
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800119 DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800120 int flags, IBinder localWin) {
121 mService = service;
Daichi Hirono58e25e12017-10-25 15:48:08 +0900122 mDragDropController = service.mDragDropController;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800123 mToken = token;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800124 mSurfaceControl = surface;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800125 mFlags = flags;
126 mLocalWin = localWin;
127 mNotifiedWindows = new ArrayList<WindowState>();
128 }
129
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900130 /**
131 * After calling this, DragDropController#onDragStateClosedLocked is invoked, which causes
132 * DragDropController#mDragState becomes null.
133 */
134 void closeLocked() {
135 // Unregister the input interceptor.
136 if (mInputInterceptor != null) {
137 if (DEBUG_DRAG)
138 Slog.d(TAG_WM, "unregistering drag input channel");
139
140 // Input channel should be disposed on the thread where the input is being handled.
141 mDragDropController.sendHandlerMessage(
142 MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
143 mInputInterceptor = null;
144 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
145 }
146
147 // Send drag end broadcast if drag start has been sent.
148 if (mDragInProgress) {
149 final int myPid = Process.myPid();
150
151 if (DEBUG_DRAG) {
152 Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
153 }
154 for (WindowState ws : mNotifiedWindows) {
155 float x = 0;
156 float y = 0;
157 if (!mDragResult && (ws.mSession.mPid == mPid)) {
158 // Report unconsumed drop location back to the app that started the drag.
159 x = mCurrentX;
160 y = mCurrentY;
161 }
162 DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
163 x, y, null, null, null, null, mDragResult);
164 try {
165 ws.mClient.dispatchDragEvent(evt);
166 } catch (RemoteException e) {
167 Slog.w(TAG_WM, "Unable to drag-end window " + ws);
168 }
169 // if the current window is in the same process,
170 // the dispatch has already recycled the event
171 if (myPid != ws.mSession.mPid) {
172 evt.recycle();
173 }
174 }
175 mNotifiedWindows.clear();
176 mDragInProgress = false;
177 }
178
179 // Take the cursor back if it has been changed.
180 if (isFromSource(InputDevice.SOURCE_MOUSE)) {
181 mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
182 mTouchSource = 0;
183 }
184
185 // Clear the internal variables.
186 if (mSurfaceControl != null) {
187 mSurfaceControl.destroy();
188 mSurfaceControl = null;
189 }
190 if (mAnimator != null && !mAnimationCompleted) {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900191 Slog.wtf(TAG_WM,
192 "Unexpectedly destroying mSurfaceControl while animation is running");
193 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800194 mFlags = 0;
195 mLocalWin = null;
196 mToken = null;
197 mData = null;
198 mThumbOffsetX = mThumbOffsetY = 0;
199 mNotifiedWindows = null;
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900200
201 // Notifies the controller that the drag state is closed.
202 mDragDropController.onDragStateClosedLocked(this);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800203 }
204
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700205 class InputInterceptor {
206 InputChannel mServerChannel, mClientChannel;
207 DragInputEventReceiver mInputEventReceiver;
208 InputApplicationHandle mDragApplicationHandle;
209 InputWindowHandle mDragWindowHandle;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800210
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700211 InputInterceptor(Display display) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800212 InputChannel[] channels = InputChannel.openInputChannelPair("drag");
213 mServerChannel = channels[0];
214 mClientChannel = channels[1];
215 mService.mInputManager.registerInputChannel(mServerChannel, null);
Daichi Hirono52cb2152017-09-11 15:29:42 +0900216 mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
Daichi Hirono768012e2017-10-30 10:05:37 +0900217 mService.mH.getLooper(), mDragDropController);
Jeff Brownea426552011-07-18 16:53:48 -0700218
219 mDragApplicationHandle = new InputApplicationHandle(null);
220 mDragApplicationHandle.name = "drag";
221 mDragApplicationHandle.dispatchingTimeoutNanos =
222 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
223
Vladislav Kaznacheev3787de12016-12-21 10:36:35 -0800224 mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, null,
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800225 display.getDisplayId());
Jeff Brownea426552011-07-18 16:53:48 -0700226 mDragWindowHandle.name = "drag";
227 mDragWindowHandle.inputChannel = mServerChannel;
Daichi Hirono58e25e12017-10-25 15:48:08 +0900228 mDragWindowHandle.layer = getDragLayerLocked();
Jeff Brownea426552011-07-18 16:53:48 -0700229 mDragWindowHandle.layoutParamsFlags = 0;
230 mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
231 mDragWindowHandle.dispatchingTimeoutNanos =
232 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
233 mDragWindowHandle.visible = true;
234 mDragWindowHandle.canReceiveKeys = false;
235 mDragWindowHandle.hasFocus = true;
236 mDragWindowHandle.hasWallpaper = false;
237 mDragWindowHandle.paused = false;
238 mDragWindowHandle.ownerPid = Process.myPid();
239 mDragWindowHandle.ownerUid = Process.myUid();
240 mDragWindowHandle.inputFeatures = 0;
241 mDragWindowHandle.scaleFactor = 1.0f;
242
243 // The drag window cannot receive new touches.
244 mDragWindowHandle.touchableRegion.setEmpty();
245
246 // The drag window covers the entire display
247 mDragWindowHandle.frameLeft = 0;
248 mDragWindowHandle.frameTop = 0;
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800249 mDragWindowHandle.frameRight = mDisplaySize.x;
250 mDragWindowHandle.frameBottom = mDisplaySize.y;
Jeff Brown01a98dd2011-09-20 15:08:29 -0700251
252 // Pause rotations before a drag.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800253 if (DEBUG_ORIENTATION) {
254 Slog.d(TAG_WM, "Pausing rotation during drag");
Jeff Brown01a98dd2011-09-20 15:08:29 -0700255 }
256 mService.pauseRotationLocked();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800257 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800258
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700259 void tearDown() {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800260 mService.mInputManager.unregisterInputChannel(mServerChannel);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800261 mInputEventReceiver.dispose();
262 mInputEventReceiver = null;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800263 mClientChannel.dispose();
264 mServerChannel.dispose();
265 mClientChannel = null;
266 mServerChannel = null;
Jeff Browncc4f7db2011-08-30 20:34:48 -0700267
268 mDragWindowHandle = null;
269 mDragApplicationHandle = null;
Jeff Brown01a98dd2011-09-20 15:08:29 -0700270
271 // Resume rotations after a drag.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800272 if (DEBUG_ORIENTATION) {
273 Slog.d(TAG_WM, "Resuming rotation after drag");
Jeff Brown01a98dd2011-09-20 15:08:29 -0700274 }
275 mService.resumeRotationLocked();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800276 }
277 }
278
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700279 InputChannel getInputChannel() {
280 return mInputInterceptor == null ? null : mInputInterceptor.mServerChannel;
281 }
282
283 InputWindowHandle getInputWindowHandle() {
284 return mInputInterceptor == null ? null : mInputInterceptor.mDragWindowHandle;
285 }
286
287 /**
288 * @param display The Display that the window being dragged is on.
289 */
290 void register(Display display) {
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800291 display.getRealSize(mDisplaySize);
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700292 if (DEBUG_DRAG) Slog.d(TAG_WM, "registering drag input channel");
293 if (mInputInterceptor != null) {
294 Slog.e(TAG_WM, "Duplicate register of drag input channel");
295 } else {
296 mInputInterceptor = new InputInterceptor(display);
297 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
298 }
299 }
300
Daichi Hirono58e25e12017-10-25 15:48:08 +0900301 int getDragLayerLocked() {
Wale Ogunwale5cd907d2017-01-26 14:14:08 -0800302 return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_DRAG)
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800303 * WindowManagerService.TYPE_LAYER_MULTIPLIER
304 + WindowManagerService.TYPE_LAYER_OFFSET;
305 }
306
307 /* call out to each visible window/session informing it about the drag
308 */
Daichi Hirono58e25e12017-10-25 15:48:08 +0900309 void broadcastDragStartedLocked(final float touchX, final float touchY) {
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800310 mOriginalX = mCurrentX = touchX;
311 mOriginalY = mCurrentY = touchY;
312
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800313 // Cache a base-class instance of the clip metadata so that parceling
314 // works correctly in calling out to the apps.
315 mDataDescription = (mData != null) ? mData.getDescription() : null;
316 mNotifiedWindows.clear();
317 mDragInProgress = true;
318
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800319 mSourceUserId = UserHandle.getUserId(mUid);
320
321 final IUserManager userManager =
322 (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
323 try {
324 mCrossProfileCopyAllowed = !userManager.getUserRestrictions(mSourceUserId).getBoolean(
325 UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
326 } catch (RemoteException e) {
327 Slog.e(TAG_WM, "Remote Exception calling UserManager: " + e);
328 mCrossProfileCopyAllowed = false;
329 }
330
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800331 if (DEBUG_DRAG) {
332 Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800333 }
334
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800335 mDisplayContent.forAllWindows(w -> {
Daichi Hirono58e25e12017-10-25 15:48:08 +0900336 sendDragStartedLocked(w, touchX, touchY, mDataDescription);
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800337 }, false /* traverseTopToBottom */ );
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800338 }
339
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800340 /* helper - send a ACTION_DRAG_STARTED event, if the
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800341 * designated window is potentially a drop recipient. There are race situations
342 * around DRAG_ENDED broadcast, so we make sure that once we've declared that
343 * the drag has ended, we never send out another DRAG_STARTED for this drag action.
344 *
345 * This method clones the 'event' parameter if it's being delivered to the same
346 * process, so it's safe for the caller to call recycle() on the event afterwards.
347 */
Daichi Hirono58e25e12017-10-25 15:48:08 +0900348 private void sendDragStartedLocked(WindowState newWin, float touchX, float touchY,
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800349 ClipDescription desc) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800350 if (mDragInProgress && isValidDropTarget(newWin)) {
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700351 DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700352 touchX, touchY, null, desc, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800353 try {
354 newWin.mClient.dispatchDragEvent(event);
355 // track each window that we've notified that the drag is starting
356 mNotifiedWindows.add(newWin);
357 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800358 Slog.w(TAG_WM, "Unable to drag-start window " + newWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800359 } finally {
360 // if the callee was local, the dispatch has already recycled the event
361 if (Process.myPid() != newWin.mSession.mPid) {
362 event.recycle();
363 }
364 }
365 }
366 }
367
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800368 private boolean isValidDropTarget(WindowState targetWin) {
369 if (targetWin == null) {
370 return false;
371 }
372 if (!targetWin.isPotentialDragTarget()) {
373 return false;
374 }
Yorke Lee0e852472016-06-15 10:03:18 -0700375 if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0 || !targetWindowSupportsGlobalDrag(targetWin)) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800376 // Drag is limited to the current window.
377 if (mLocalWin != targetWin.mClient.asBinder()) {
378 return false;
379 }
380 }
381
382 return mCrossProfileCopyAllowed ||
383 mSourceUserId == UserHandle.getUserId(targetWin.getOwningUid());
384 }
385
Yorke Lee0e852472016-06-15 10:03:18 -0700386 private boolean targetWindowSupportsGlobalDrag(WindowState targetWin) {
387 // Global drags are limited to system windows, and windows for apps that are targeting N and
388 // above.
389 return targetWin.mAppToken == null
Wale Ogunwale72919d22016-12-08 18:58:50 -0800390 || targetWin.mAppToken.mTargetSdk >= Build.VERSION_CODES.N;
Yorke Lee0e852472016-06-15 10:03:18 -0700391 }
392
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800393 /* helper - send a ACTION_DRAG_STARTED event only if the window has not
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800394 * previously been notified, i.e. it became visible after the drag operation
395 * was begun. This is a rare case.
396 */
Daichi Hirono58e25e12017-10-25 15:48:08 +0900397 void sendDragStartedIfNeededLocked(WindowState newWin) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800398 if (mDragInProgress) {
399 // If we have sent the drag-started, we needn't do so again
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800400 if (isWindowNotified(newWin)) {
401 return;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800402 }
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800403 if (DEBUG_DRAG) {
404 Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800405 }
Daichi Hirono58e25e12017-10-25 15:48:08 +0900406 sendDragStartedLocked(newWin, mCurrentX, mCurrentY, mDataDescription);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800407 }
408 }
409
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800410 private boolean isWindowNotified(WindowState newWin) {
411 for (WindowState ws : mNotifiedWindows) {
412 if (ws == newWin) {
413 return true;
414 }
415 }
416 return false;
417 }
418
Daichi Hirono58e25e12017-10-25 15:48:08 +0900419 void endDragLocked() {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900420 if (mAnimator != null) {
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800421 return;
422 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800423 if (!mDragResult) {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900424 mAnimator = createReturnAnimationLocked();
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900425 return; // Will call closeLocked() when the animation is done.
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800426 }
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900427 closeLocked();
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800428 }
429
Daichi Hirono58e25e12017-10-25 15:48:08 +0900430 void cancelDragLocked() {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900431 if (mAnimator != null) {
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800432 return;
433 }
Daichi Hirono4a700b12017-10-04 15:49:35 +0900434 if (!mDragInProgress) {
435 // This can happen if an app invokes Session#cancelDragAndDrop before
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900436 // Session#performDrag. Reset the drag state without playing the cancel animation
437 // because H.DRAG_START_TIMEOUT may be sent to WindowManagerService, which will cause
438 // DragState#reset() while playing the cancel animation.
439 closeLocked();
Daichi Hirono4a700b12017-10-04 15:49:35 +0900440 return;
441 }
442 mAnimator = createCancelAnimationLocked();
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800443 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800444
Daichi Hirono58e25e12017-10-25 15:48:08 +0900445 void notifyMoveLocked(float x, float y) {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900446 if (mAnimator != null) {
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800447 return;
448 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800449 mCurrentX = x;
450 mCurrentY = y;
451
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800452 // Move the surface to the given touch
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800453 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
Daichi Hirono58e25e12017-10-25 15:48:08 +0900454 TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
Robert Carr68e5c9e2016-09-14 10:50:09 -0700455 mService.openSurfaceTransaction();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800456 try {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800457 mSurfaceControl.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800458 if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " DRAG "
Mathias Agopian29479eb2013-02-14 14:36:04 -0800459 + mSurfaceControl + ": pos=(" +
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800460 (int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")");
461 } finally {
Adrian Roos111aff92017-09-27 18:11:46 +0200462 mService.closeSurfaceTransaction("notifyMoveLw");
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800463 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
Daichi Hirono58e25e12017-10-25 15:48:08 +0900464 TAG_WM, "<<< CLOSE TRANSACTION notifyMoveLocked");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800465 }
Daichi Hirono58e25e12017-10-25 15:48:08 +0900466 notifyLocationLocked(x, y);
Vladislav Kaznacheevd0ed8932016-01-15 15:37:05 -0800467 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800468
Daichi Hirono58e25e12017-10-25 15:48:08 +0900469 void notifyLocationLocked(float x, float y) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800470 // Tell the affected window
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800471 WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
Vladislav Kaznacheev598d40d2016-04-19 15:24:52 -0700472 if (touchedWin != null && !isWindowNotified(touchedWin)) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800473 // The drag point is over a window which was not notified about a drag start.
474 // Pretend it's over empty space.
475 touchedWin = null;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800476 }
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800477
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800478 try {
Vladislav Kaznacheevd0ed8932016-01-15 15:37:05 -0800479 final int myPid = Process.myPid();
480
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800481 // have we dragged over a new window?
482 if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800483 if (DEBUG_DRAG) {
484 Slog.d(TAG_WM, "sending DRAG_EXITED to " + mTargetWindow);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800485 }
486 // force DRAG_EXITED_EVENT if appropriate
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700487 DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
Vladislav Kaznacheevcc010b22016-01-21 16:24:40 -0800488 0, 0, null, null, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800489 mTargetWindow.mClient.dispatchDragEvent(evt);
490 if (myPid != mTargetWindow.mSession.mPid) {
491 evt.recycle();
492 }
493 }
494 if (touchedWin != null) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800495 if (false && DEBUG_DRAG) {
496 Slog.d(TAG_WM, "sending DRAG_LOCATION to " + touchedWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800497 }
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700498 DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700499 x, y, null, null, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800500 touchedWin.mClient.dispatchDragEvent(evt);
501 if (myPid != touchedWin.mSession.mPid) {
502 evt.recycle();
503 }
504 }
505 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800506 Slog.w(TAG_WM, "can't send drag notification to windows");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800507 }
508 mTargetWindow = touchedWin;
509 }
510
Daichi Hirono768012e2017-10-30 10:05:37 +0900511 /**
512 * Finds the drop target and tells it about the data. If the drop event is not sent to the
513 * target, invokes {@code endDragLocked} immediately.
514 */
515 void notifyDropLocked(float x, float y) {
Daichi Hirono4a700b12017-10-04 15:49:35 +0900516 if (mAnimator != null) {
Daichi Hirono768012e2017-10-30 10:05:37 +0900517 return;
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800518 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800519 mCurrentX = x;
520 mCurrentY = y;
521
Daichi Hirono768012e2017-10-30 10:05:37 +0900522 final WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800523
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800524 if (!isWindowNotified(touchedWin)) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800525 // "drop" outside a valid window -- no recipient to apply a
526 // timeout to, and we can send the drag-ended message immediately.
527 mDragResult = false;
Daichi Hirono768012e2017-10-30 10:05:37 +0900528 endDragLocked();
529 return;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800530 }
531
Daichi Hirono768012e2017-10-30 10:05:37 +0900532 if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800533
534 final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
535
Daichi Hirono768012e2017-10-30 10:05:37 +0900536 final DragAndDropPermissionsHandler dragAndDropPermissions;
537 if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700538 dragAndDropPermissions = new DragAndDropPermissionsHandler(
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800539 mData,
540 mUid,
541 touchedWin.getOwningPackage(),
542 mFlags & DRAG_FLAGS_URI_PERMISSIONS,
543 mSourceUserId,
544 targetUserId);
Daichi Hirono768012e2017-10-30 10:05:37 +0900545 } else {
546 dragAndDropPermissions = null;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800547 }
548 if (mSourceUserId != targetUserId){
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800549 mData.fixUris(mSourceUserId);
550 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800551 final int myPid = Process.myPid();
552 final IBinder token = touchedWin.mClient.asBinder();
Daichi Hirono768012e2017-10-30 10:05:37 +0900553 final DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700554 null, null, mData, dragAndDropPermissions, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800555 try {
556 touchedWin.mClient.dispatchDragEvent(evt);
557
558 // 5 second timeout for this window to respond to the drop
Daichi Hirono58e25e12017-10-25 15:48:08 +0900559 mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800560 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800561 Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
Daichi Hirono768012e2017-10-30 10:05:37 +0900562 endDragLocked();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800563 } finally {
564 if (myPid != touchedWin.mSession.mPid) {
565 evt.recycle();
566 }
567 }
568 mToken = token;
Daichi Hirono58e25e12017-10-25 15:48:08 +0900569 }
570
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700571 private static DragEvent obtainDragEvent(WindowState win, int action,
572 float x, float y, Object localState,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700573 ClipDescription description, ClipData data,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700574 IDragAndDropPermissions dragAndDropPermissions,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700575 boolean result) {
Vladislav Kaznacheev989b58a2016-02-10 12:19:33 -0800576 final float winX = win.translateToWindowX(x);
577 final float winY = win.translateToWindowY(y);
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700578 return DragEvent.obtain(action, winX, winY, localState, description, data,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700579 dragAndDropPermissions, result);
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700580 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800581
Daichi Hirono4a700b12017-10-04 15:49:35 +0900582 private ValueAnimator createReturnAnimationLocked() {
583 final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
584 PropertyValuesHolder.ofFloat(
585 ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX,
586 mOriginalX - mThumbOffsetX),
587 PropertyValuesHolder.ofFloat(
588 ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY,
589 mOriginalY - mThumbOffsetY),
590 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 1),
591 PropertyValuesHolder.ofFloat(
592 ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, mOriginalAlpha / 2));
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800593
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800594 final float translateX = mOriginalX - mCurrentX;
595 final float translateY = mOriginalY - mCurrentY;
Vladislav Kaznacheevb3665f12016-11-18 15:06:08 -0800596 // Adjust the duration to the travel distance.
597 final double travelDistance = Math.sqrt(translateX * translateX + translateY * translateY);
598 final double displayDiagonal =
599 Math.sqrt(mDisplaySize.x * mDisplaySize.x + mDisplaySize.y * mDisplaySize.y);
600 final long duration = MIN_ANIMATION_DURATION_MS + (long) (travelDistance / displayDiagonal
601 * (MAX_ANIMATION_DURATION_MS - MIN_ANIMATION_DURATION_MS));
Daichi Hirono4a700b12017-10-04 15:49:35 +0900602 final AnimationListener listener = new AnimationListener();
603 animator.setDuration(duration);
604 animator.setInterpolator(mCubicEaseOutInterpolator);
605 animator.addListener(listener);
606 animator.addUpdateListener(listener);
607
608 mService.mAnimationHandler.post(() -> animator.start());
609 return animator;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800610 }
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800611
Daichi Hirono4a700b12017-10-04 15:49:35 +0900612 private ValueAnimator createCancelAnimationLocked() {
613 final ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(
614 PropertyValuesHolder.ofFloat(
615 ANIMATED_PROPERTY_X, mCurrentX - mThumbOffsetX, mCurrentX),
616 PropertyValuesHolder.ofFloat(
617 ANIMATED_PROPERTY_Y, mCurrentY - mThumbOffsetY, mCurrentY),
618 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_SCALE, 1, 0),
619 PropertyValuesHolder.ofFloat(ANIMATED_PROPERTY_ALPHA, mOriginalAlpha, 0));
620 final AnimationListener listener = new AnimationListener();
621 animator.setDuration(MIN_ANIMATION_DURATION_MS);
622 animator.setInterpolator(mCubicEaseOutInterpolator);
623 animator.addListener(listener);
624 animator.addUpdateListener(listener);
625
626 mService.mAnimationHandler.post(() -> animator.start());
627 return animator;
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800628 }
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800629
630 private boolean isFromSource(int source) {
631 return (mTouchSource & source) == source;
632 }
633
Daichi Hirono58e25e12017-10-25 15:48:08 +0900634 void overridePointerIconLocked(int touchSource) {
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800635 mTouchSource = touchSource;
636 if (isFromSource(InputDevice.SOURCE_MOUSE)) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100637 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_GRABBING);
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800638 }
639 }
Daichi Hirono4a700b12017-10-04 15:49:35 +0900640
Daichi Hirono4a700b12017-10-04 15:49:35 +0900641 private class AnimationListener
642 implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
643 @Override
644 public void onAnimationUpdate(ValueAnimator animation) {
645 try (final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
646 transaction.setPosition(
647 mSurfaceControl,
648 (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_X),
649 (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_Y));
650 transaction.setAlpha(
651 mSurfaceControl,
652 (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_ALPHA));
653 transaction.setMatrix(
654 mSurfaceControl,
655 (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE), 0,
656 0, (float) mAnimator.getAnimatedValue(ANIMATED_PROPERTY_SCALE));
657 transaction.apply();
658 }
659 }
660
661 @Override
662 public void onAnimationStart(Animator animator) {}
663
664 @Override
665 public void onAnimationCancel(Animator animator) {}
666
667 @Override
668 public void onAnimationRepeat(Animator animator) {}
669
670 @Override
671 public void onAnimationEnd(Animator animator) {
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900672 mAnimationCompleted = true;
Daichi Hirono4a700b12017-10-04 15:49:35 +0900673 // Updating mDragState requires the WM lock so continues it on the out of
674 // AnimationThread.
Daichi Hirono58e25e12017-10-25 15:48:08 +0900675 mDragDropController.sendHandlerMessage(MSG_ANIMATION_END, null);
Daichi Hirono4a700b12017-10-04 15:49:35 +0900676 }
677 }
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800678}