blob: d0167bb6f00b3812495c7fcd411f8534dc12e4d5 [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
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080019import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
20import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
21import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
22import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
23import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080024
25import android.content.ClipData;
26import android.content.ClipDescription;
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -080027import android.content.Context;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080028import android.graphics.Matrix;
Craig Mautner39834192012-09-02 07:47:24 -070029import android.graphics.Point;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080030import android.hardware.input.InputManager;
Yorke Lee0e852472016-06-15 10:03:18 -070031import android.os.Build;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080032import android.os.IBinder;
33import android.os.Message;
34import android.os.Process;
35import android.os.RemoteException;
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -080036import android.os.ServiceManager;
37import android.os.UserHandle;
38import android.os.UserManager;
39import android.os.IUserManager;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080040import android.util.Slog;
Craig Mautner39834192012-09-02 07:47:24 -070041import android.view.Display;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080042import android.view.DragEvent;
43import android.view.InputChannel;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080044import android.view.InputDevice;
45import android.view.PointerIcon;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080046import android.view.SurfaceControl;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080047import android.view.View;
48import android.view.WindowManager;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080049import android.view.animation.AlphaAnimation;
50import android.view.animation.Animation;
51import android.view.animation.AnimationSet;
52import android.view.animation.DecelerateInterpolator;
53import android.view.animation.Interpolator;
54import android.view.animation.ScaleAnimation;
55import android.view.animation.Transformation;
56import android.view.animation.TranslateAnimation;
57
58import com.android.server.input.InputApplicationHandle;
59import com.android.server.input.InputWindowHandle;
60import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
61import com.android.server.wm.WindowManagerService.H;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080062
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -070063import com.android.internal.view.IDragAndDropPermissions;
Vladislav Kaznacheev9149d2b2015-12-15 12:16:28 -080064
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080065import java.util.ArrayList;
66
67/**
68 * Drag/drop state
69 */
70class DragState {
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -080071 private static final long ANIMATION_DURATION_MS = 500;
72
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -080073 private static final int DRAG_FLAGS_URI_ACCESS = View.DRAG_FLAG_GLOBAL_URI_READ |
74 View.DRAG_FLAG_GLOBAL_URI_WRITE;
75
76 private static final int DRAG_FLAGS_URI_PERMISSIONS = DRAG_FLAGS_URI_ACCESS |
77 View.DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION |
78 View.DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION;
79
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080080 final WindowManagerService mService;
81 IBinder mToken;
Mathias Agopian29479eb2013-02-14 14:36:04 -080082 SurfaceControl mSurfaceControl;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080083 int mFlags;
84 IBinder mLocalWin;
Vladislav Kaznacheevc7482412015-11-05 14:03:07 -080085 int mPid;
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -070086 int mUid;
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -080087 int mSourceUserId;
88 boolean mCrossProfileCopyAllowed;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080089 ClipData mData;
90 ClipDescription mDataDescription;
Vladislav Kaznacheevba761122016-01-22 12:09:45 -080091 int mTouchSource;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080092 boolean mDragResult;
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -080093 float mOriginalAlpha;
94 float mOriginalX, mOriginalY;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080095 float mCurrentX, mCurrentY;
96 float mThumbOffsetX, mThumbOffsetY;
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -070097 InputInterceptor mInputInterceptor;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080098 WindowState mTargetWindow;
99 ArrayList<WindowState> mNotifiedWindows;
100 boolean mDragInProgress;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800101 DisplayContent mDisplayContent;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800102
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800103 private Animation mAnimation;
104 final Transformation mTransformation = new Transformation();
105 private final Interpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
106
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800107 DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800108 int flags, IBinder localWin) {
109 mService = service;
110 mToken = token;
Mathias Agopian29479eb2013-02-14 14:36:04 -0800111 mSurfaceControl = surface;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800112 mFlags = flags;
113 mLocalWin = localWin;
114 mNotifiedWindows = new ArrayList<WindowState>();
115 }
116
117 void reset() {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800118 if (mSurfaceControl != null) {
119 mSurfaceControl.destroy();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800120 }
Mathias Agopian29479eb2013-02-14 14:36:04 -0800121 mSurfaceControl = null;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800122 mFlags = 0;
123 mLocalWin = null;
124 mToken = null;
125 mData = null;
126 mThumbOffsetX = mThumbOffsetY = 0;
127 mNotifiedWindows = null;
128 }
129
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700130 class InputInterceptor {
131 InputChannel mServerChannel, mClientChannel;
132 DragInputEventReceiver mInputEventReceiver;
133 InputApplicationHandle mDragApplicationHandle;
134 InputWindowHandle mDragWindowHandle;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800135
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700136 InputInterceptor(Display display) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800137 InputChannel[] channels = InputChannel.openInputChannelPair("drag");
138 mServerChannel = channels[0];
139 mClientChannel = channels[1];
140 mService.mInputManager.registerInputChannel(mServerChannel, null);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800141 mInputEventReceiver = mService.new DragInputEventReceiver(mClientChannel,
142 mService.mH.getLooper());
Jeff Brownea426552011-07-18 16:53:48 -0700143
144 mDragApplicationHandle = new InputApplicationHandle(null);
145 mDragApplicationHandle.name = "drag";
146 mDragApplicationHandle.dispatchingTimeoutNanos =
147 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
148
Craig Mautner59c00972012-07-30 12:10:24 -0700149 mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800150 display.getDisplayId());
Jeff Brownea426552011-07-18 16:53:48 -0700151 mDragWindowHandle.name = "drag";
152 mDragWindowHandle.inputChannel = mServerChannel;
153 mDragWindowHandle.layer = getDragLayerLw();
154 mDragWindowHandle.layoutParamsFlags = 0;
155 mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
156 mDragWindowHandle.dispatchingTimeoutNanos =
157 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
158 mDragWindowHandle.visible = true;
159 mDragWindowHandle.canReceiveKeys = false;
160 mDragWindowHandle.hasFocus = true;
161 mDragWindowHandle.hasWallpaper = false;
162 mDragWindowHandle.paused = false;
163 mDragWindowHandle.ownerPid = Process.myPid();
164 mDragWindowHandle.ownerUid = Process.myUid();
165 mDragWindowHandle.inputFeatures = 0;
166 mDragWindowHandle.scaleFactor = 1.0f;
167
168 // The drag window cannot receive new touches.
169 mDragWindowHandle.touchableRegion.setEmpty();
170
171 // The drag window covers the entire display
172 mDragWindowHandle.frameLeft = 0;
173 mDragWindowHandle.frameTop = 0;
Craig Mautner39834192012-09-02 07:47:24 -0700174 Point p = new Point();
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800175 display.getRealSize(p);
Craig Mautner39834192012-09-02 07:47:24 -0700176 mDragWindowHandle.frameRight = p.x;
177 mDragWindowHandle.frameBottom = p.y;
Jeff Brown01a98dd2011-09-20 15:08:29 -0700178
179 // Pause rotations before a drag.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800180 if (DEBUG_ORIENTATION) {
181 Slog.d(TAG_WM, "Pausing rotation during drag");
Jeff Brown01a98dd2011-09-20 15:08:29 -0700182 }
183 mService.pauseRotationLocked();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800184 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800185
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700186 void tearDown() {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800187 mService.mInputManager.unregisterInputChannel(mServerChannel);
Jeff Brown32cbc38552011-12-01 14:01:49 -0800188 mInputEventReceiver.dispose();
189 mInputEventReceiver = null;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800190 mClientChannel.dispose();
191 mServerChannel.dispose();
192 mClientChannel = null;
193 mServerChannel = null;
Jeff Browncc4f7db2011-08-30 20:34:48 -0700194
195 mDragWindowHandle = null;
196 mDragApplicationHandle = null;
Jeff Brown01a98dd2011-09-20 15:08:29 -0700197
198 // Resume rotations after a drag.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800199 if (DEBUG_ORIENTATION) {
200 Slog.d(TAG_WM, "Resuming rotation after drag");
Jeff Brown01a98dd2011-09-20 15:08:29 -0700201 }
202 mService.resumeRotationLocked();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800203 }
204 }
205
Vladislav Kaznacheev64b103a2016-08-10 11:49:08 -0700206 InputChannel getInputChannel() {
207 return mInputInterceptor == null ? null : mInputInterceptor.mServerChannel;
208 }
209
210 InputWindowHandle getInputWindowHandle() {
211 return mInputInterceptor == null ? null : mInputInterceptor.mDragWindowHandle;
212 }
213
214 /**
215 * @param display The Display that the window being dragged is on.
216 */
217 void register(Display display) {
218 if (DEBUG_DRAG) Slog.d(TAG_WM, "registering drag input channel");
219 if (mInputInterceptor != null) {
220 Slog.e(TAG_WM, "Duplicate register of drag input channel");
221 } else {
222 mInputInterceptor = new InputInterceptor(display);
223 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
224 }
225 }
226
227 void unregister() {
228 if (DEBUG_DRAG) Slog.d(TAG_WM, "unregistering drag input channel");
229 if (mInputInterceptor == null) {
230 Slog.e(TAG_WM, "Unregister of nonexistent drag input channel");
231 } else {
232 // Input channel should be disposed on the thread where the input is being handled.
233 mService.mH.obtainMessage(
234 H.TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor).sendToTarget();
235 mInputInterceptor = null;
236 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
237 }
238 }
239
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800240 int getDragLayerLw() {
241 return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG)
242 * WindowManagerService.TYPE_LAYER_MULTIPLIER
243 + WindowManagerService.TYPE_LAYER_OFFSET;
244 }
245
246 /* call out to each visible window/session informing it about the drag
247 */
248 void broadcastDragStartedLw(final float touchX, final float touchY) {
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800249 mOriginalX = mCurrentX = touchX;
250 mOriginalY = mCurrentY = touchY;
251
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800252 // Cache a base-class instance of the clip metadata so that parceling
253 // works correctly in calling out to the apps.
254 mDataDescription = (mData != null) ? mData.getDescription() : null;
255 mNotifiedWindows.clear();
256 mDragInProgress = true;
257
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800258 mSourceUserId = UserHandle.getUserId(mUid);
259
260 final IUserManager userManager =
261 (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
262 try {
263 mCrossProfileCopyAllowed = !userManager.getUserRestrictions(mSourceUserId).getBoolean(
264 UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
265 } catch (RemoteException e) {
266 Slog.e(TAG_WM, "Remote Exception calling UserManager: " + e);
267 mCrossProfileCopyAllowed = false;
268 }
269
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800270 if (DEBUG_DRAG) {
271 Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800272 }
273
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800274 final WindowList windows = mDisplayContent.getWindowList();
275 final int N = windows.size();
276 for (int i = 0; i < N; i++) {
277 sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800278 }
279 }
280
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800281 /* helper - send a ACTION_DRAG_STARTED event, if the
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800282 * designated window is potentially a drop recipient. There are race situations
283 * around DRAG_ENDED broadcast, so we make sure that once we've declared that
284 * the drag has ended, we never send out another DRAG_STARTED for this drag action.
285 *
286 * This method clones the 'event' parameter if it's being delivered to the same
287 * process, so it's safe for the caller to call recycle() on the event afterwards.
288 */
289 private void sendDragStartedLw(WindowState newWin, float touchX, float touchY,
290 ClipDescription desc) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800291 if (mDragInProgress && isValidDropTarget(newWin)) {
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700292 DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700293 touchX, touchY, null, desc, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800294 try {
295 newWin.mClient.dispatchDragEvent(event);
296 // track each window that we've notified that the drag is starting
297 mNotifiedWindows.add(newWin);
298 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800299 Slog.w(TAG_WM, "Unable to drag-start window " + newWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800300 } finally {
301 // if the callee was local, the dispatch has already recycled the event
302 if (Process.myPid() != newWin.mSession.mPid) {
303 event.recycle();
304 }
305 }
306 }
307 }
308
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800309 private boolean isValidDropTarget(WindowState targetWin) {
310 if (targetWin == null) {
311 return false;
312 }
313 if (!targetWin.isPotentialDragTarget()) {
314 return false;
315 }
Yorke Lee0e852472016-06-15 10:03:18 -0700316 if ((mFlags & View.DRAG_FLAG_GLOBAL) == 0 || !targetWindowSupportsGlobalDrag(targetWin)) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800317 // Drag is limited to the current window.
318 if (mLocalWin != targetWin.mClient.asBinder()) {
319 return false;
320 }
321 }
322
323 return mCrossProfileCopyAllowed ||
324 mSourceUserId == UserHandle.getUserId(targetWin.getOwningUid());
325 }
326
Yorke Lee0e852472016-06-15 10:03:18 -0700327 private boolean targetWindowSupportsGlobalDrag(WindowState targetWin) {
328 // Global drags are limited to system windows, and windows for apps that are targeting N and
329 // above.
330 return targetWin.mAppToken == null
331 || targetWin.mAppToken.targetSdk >= Build.VERSION_CODES.N;
332 }
333
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800334 /* helper - send a ACTION_DRAG_STARTED event only if the window has not
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800335 * previously been notified, i.e. it became visible after the drag operation
336 * was begun. This is a rare case.
337 */
338 void sendDragStartedIfNeededLw(WindowState newWin) {
339 if (mDragInProgress) {
340 // If we have sent the drag-started, we needn't do so again
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800341 if (isWindowNotified(newWin)) {
342 return;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800343 }
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800344 if (DEBUG_DRAG) {
345 Slog.d(TAG_WM, "need to send DRAG_STARTED to new window " + newWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800346 }
347 sendDragStartedLw(newWin, mCurrentX, mCurrentY, mDataDescription);
348 }
349 }
350
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800351 private boolean isWindowNotified(WindowState newWin) {
352 for (WindowState ws : mNotifiedWindows) {
353 if (ws == newWin) {
354 return true;
355 }
356 }
357 return false;
358 }
359
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800360 private void broadcastDragEndedLw() {
Vladislav Kaznacheev68dd2e82015-10-22 17:06:40 -0700361 final int myPid = Process.myPid();
362
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800363 if (DEBUG_DRAG) {
364 Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800365 }
Vladislav Kaznacheev68dd2e82015-10-22 17:06:40 -0700366 for (WindowState ws : mNotifiedWindows) {
Vladislav Kaznacheevc7482412015-11-05 14:03:07 -0800367 float x = 0;
368 float y = 0;
369 if (!mDragResult && (ws.mSession.mPid == mPid)) {
370 // Report unconsumed drop location back to the app that started the drag.
371 x = mCurrentX;
372 y = mCurrentY;
373 }
Vladislav Kaznacheev68dd2e82015-10-22 17:06:40 -0700374 DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
Vladislav Kaznacheevc7482412015-11-05 14:03:07 -0800375 x, y, null, null, null, null, mDragResult);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800376 try {
377 ws.mClient.dispatchDragEvent(evt);
378 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800379 Slog.w(TAG_WM, "Unable to drag-end window " + ws);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800380 }
Vladislav Kaznacheev68dd2e82015-10-22 17:06:40 -0700381 // if the current window is in the same process,
382 // the dispatch has already recycled the event
383 if (myPid != ws.mSession.mPid) {
384 evt.recycle();
385 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800386 }
387 mNotifiedWindows.clear();
388 mDragInProgress = false;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800389 }
390
391 void endDragLw() {
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800392 if (mAnimation != null) {
393 return;
394 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800395 if (!mDragResult) {
396 mAnimation = createReturnAnimationLocked();
397 mService.scheduleAnimationLocked();
398 return; // Will call cleanUpDragLw when the animation is done.
399 }
400 cleanUpDragLw();
401 }
402
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800403 void cancelDragLw() {
404 if (mAnimation != null) {
405 return;
406 }
407 mAnimation = createCancelAnimationLocked();
408 mService.scheduleAnimationLocked();
409 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800410
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800411 private void cleanUpDragLw() {
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800412 broadcastDragEndedLw();
Vladislav Kaznacheev989b58a2016-02-10 12:19:33 -0800413 if (isFromSource(InputDevice.SOURCE_MOUSE)) {
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800414 mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
Vladislav Kaznacheev989b58a2016-02-10 12:19:33 -0800415 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800416
417 // stop intercepting input
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800418 unregister();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800419
420 // free our resources and drop all the object references
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800421 reset();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800422 mService.mDragState = null;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800423 }
424
425 void notifyMoveLw(float x, float y) {
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800426 if (mAnimation != null) {
427 return;
428 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800429 mCurrentX = x;
430 mCurrentY = y;
431
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800432 // Move the surface to the given touch
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800433 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
434 TAG_WM, ">>> OPEN TRANSACTION notifyMoveLw");
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800435 SurfaceControl.openTransaction();
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800436 try {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800437 mSurfaceControl.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800438 if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " DRAG "
Mathias Agopian29479eb2013-02-14 14:36:04 -0800439 + mSurfaceControl + ": pos=(" +
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800440 (int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")");
441 } finally {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800442 SurfaceControl.closeTransaction();
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800443 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
444 TAG_WM, "<<< CLOSE TRANSACTION notifyMoveLw");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800445 }
Vladislav Kaznacheevd0ed8932016-01-15 15:37:05 -0800446 notifyLocationLw(x, y);
447 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800448
Vladislav Kaznacheevd0ed8932016-01-15 15:37:05 -0800449 void notifyLocationLw(float x, float y) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800450 // Tell the affected window
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800451 WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
Vladislav Kaznacheev598d40d2016-04-19 15:24:52 -0700452 if (touchedWin != null && !isWindowNotified(touchedWin)) {
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800453 // The drag point is over a window which was not notified about a drag start.
454 // Pretend it's over empty space.
455 touchedWin = null;
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800456 }
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800457
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800458 try {
Vladislav Kaznacheevd0ed8932016-01-15 15:37:05 -0800459 final int myPid = Process.myPid();
460
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800461 // have we dragged over a new window?
462 if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800463 if (DEBUG_DRAG) {
464 Slog.d(TAG_WM, "sending DRAG_EXITED to " + mTargetWindow);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800465 }
466 // force DRAG_EXITED_EVENT if appropriate
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700467 DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
Vladislav Kaznacheevcc010b22016-01-21 16:24:40 -0800468 0, 0, null, null, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800469 mTargetWindow.mClient.dispatchDragEvent(evt);
470 if (myPid != mTargetWindow.mSession.mPid) {
471 evt.recycle();
472 }
473 }
474 if (touchedWin != null) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800475 if (false && DEBUG_DRAG) {
476 Slog.d(TAG_WM, "sending DRAG_LOCATION to " + touchedWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800477 }
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700478 DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700479 x, y, null, null, null, null, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800480 touchedWin.mClient.dispatchDragEvent(evt);
481 if (myPid != touchedWin.mSession.mPid) {
482 evt.recycle();
483 }
484 }
485 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800486 Slog.w(TAG_WM, "can't send drag notification to windows");
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800487 }
488 mTargetWindow = touchedWin;
489 }
490
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800491 // Find the drop target and tell it about the data. Returns 'true' if we can immediately
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800492 // dispatch the global drag-ended message, 'false' if we need to wait for a
493 // result from the recipient.
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800494 boolean notifyDropLw(float x, float y) {
Vladislav Kaznacheeva56b2b92015-11-20 18:30:21 -0800495 if (mAnimation != null) {
496 return false;
497 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800498 mCurrentX = x;
499 mCurrentY = y;
500
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800501 WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
502
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800503 if (!isWindowNotified(touchedWin)) {
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800504 // "drop" outside a valid window -- no recipient to apply a
505 // timeout to, and we can send the drag-ended message immediately.
506 mDragResult = false;
507 return true;
508 }
509
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800510 if (DEBUG_DRAG) {
511 Slog.d(TAG_WM, "sending DROP to " + touchedWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800512 }
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800513
514 final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
515
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700516 DragAndDropPermissionsHandler dragAndDropPermissions = null;
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800517 if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
518 (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700519 dragAndDropPermissions = new DragAndDropPermissionsHandler(
Vladislav Kaznacheev5d6bdeb2016-02-12 17:07:20 -0800520 mData,
521 mUid,
522 touchedWin.getOwningPackage(),
523 mFlags & DRAG_FLAGS_URI_PERMISSIONS,
524 mSourceUserId,
525 targetUserId);
526 }
527 if (mSourceUserId != targetUserId){
Vladislav Kaznacheevda2f1942016-02-11 18:58:41 -0800528 mData.fixUris(mSourceUserId);
529 }
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800530 final int myPid = Process.myPid();
531 final IBinder token = touchedWin.mClient.asBinder();
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700532 DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700533 null, null, mData, dragAndDropPermissions, false);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800534 try {
535 touchedWin.mClient.dispatchDragEvent(evt);
536
537 // 5 second timeout for this window to respond to the drop
538 mService.mH.removeMessages(H.DRAG_END_TIMEOUT, token);
539 Message msg = mService.mH.obtainMessage(H.DRAG_END_TIMEOUT, token);
540 mService.mH.sendMessageDelayed(msg, 5000);
541 } catch (RemoteException e) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800542 Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
Dianne Hackborn6e1eb762011-02-17 16:07:28 -0800543 return true;
544 } finally {
545 if (myPid != touchedWin.mSession.mPid) {
546 evt.recycle();
547 }
548 }
549 mToken = token;
550 return false;
551 }
552
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700553 private static DragEvent obtainDragEvent(WindowState win, int action,
554 float x, float y, Object localState,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700555 ClipDescription description, ClipData data,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700556 IDragAndDropPermissions dragAndDropPermissions,
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700557 boolean result) {
Vladislav Kaznacheev989b58a2016-02-10 12:19:33 -0800558 final float winX = win.translateToWindowX(x);
559 final float winY = win.translateToWindowY(y);
Vladislav Kaznacheevede5f542015-07-15 18:04:04 -0700560 return DragEvent.obtain(action, winX, winY, localState, description, data,
Vladislav Kaznacheev377c3282016-04-20 14:22:23 -0700561 dragAndDropPermissions, result);
Dianne Hackbornffb3d932011-05-17 17:44:51 -0700562 }
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800563
564 boolean stepAnimationLocked(long currentTimeMs) {
565 if (mAnimation == null) {
566 return false;
567 }
568
569 mTransformation.clear();
570 if (!mAnimation.getTransformation(currentTimeMs, mTransformation)) {
571 cleanUpDragLw();
572 return false;
573 }
574
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800575 mTransformation.getMatrix().postTranslate(
576 mCurrentX - mThumbOffsetX, mCurrentY - mThumbOffsetY);
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800577 final float tmpFloats[] = mService.mTmpFloats;
578 mTransformation.getMatrix().getValues(tmpFloats);
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800579 mSurfaceControl.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800580 mSurfaceControl.setAlpha(mTransformation.getAlpha());
581 mSurfaceControl.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
582 tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
583 return true;
584 }
585
586 private Animation createReturnAnimationLocked() {
587 final AnimationSet set = new AnimationSet(false);
588 set.addAnimation(new TranslateAnimation(
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800589 0, mOriginalX - mCurrentX, 0, mOriginalY - mCurrentY));
Vladislav Kaznacheev8b6f38c2015-11-19 16:00:28 -0800590 set.addAnimation(new AlphaAnimation(mOriginalAlpha, mOriginalAlpha / 2));
591 set.setDuration(ANIMATION_DURATION_MS);
592 set.setInterpolator(mCubicEaseOutInterpolator);
593 set.initialize(0, 0, 0, 0);
594 set.start(); // Will start on the first call to getTransformation.
595 return set;
596 }
Vladislav Kaznacheevce2aef92015-11-20 18:49:59 -0800597
598 private Animation createCancelAnimationLocked() {
599 final AnimationSet set = new AnimationSet(false);
600 set.addAnimation(new ScaleAnimation(1, 0, 1, 0, mThumbOffsetX, mThumbOffsetY));
601 set.addAnimation(new AlphaAnimation(mOriginalAlpha, 0));
602 set.setDuration(ANIMATION_DURATION_MS);
603 set.setInterpolator(mCubicEaseOutInterpolator);
604 set.initialize(0, 0, 0, 0);
605 set.start(); // Will start on the first call to getTransformation.
606 return set;
607 }
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800608
609 private boolean isFromSource(int source) {
610 return (mTouchSource & source) == source;
611 }
612
613 void overridePointerIconLw(int touchSource) {
614 mTouchSource = touchSource;
615 if (isFromSource(InputDevice.SOURCE_MOUSE)) {
Michael Wrightf9d9ce772016-05-13 17:44:16 +0100616 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_GRABBING);
Vladislav Kaznacheevba761122016-01-22 12:09:45 -0800617 }
618 }
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800619}