blob: a667d679ee9472cf15407954a56d1aa30d31e496 [file] [log] [blame]
Daichi Hironodf5cf622017-09-11 14:59:26 +09001/*
2 * Copyright (C) 2017 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 Hironodf5cf622017-09-11 14:59:26 +090019import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
20import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
Daichi Hironodf5cf622017-09-11 14:59:26 +090021import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
22
Daichi Hirono3c6c95e2017-09-13 12:23:57 +090023import android.annotation.NonNull;
Daichi Hironodf5cf622017-09-11 14:59:26 +090024import android.content.ClipData;
25import android.os.Binder;
Daichi Hirono58e25e12017-10-25 15:48:08 +090026import android.os.Handler;
Daichi Hironodf5cf622017-09-11 14:59:26 +090027import android.os.IBinder;
Daichi Hirono58e25e12017-10-25 15:48:08 +090028import android.os.Looper;
Daichi Hironodf5cf622017-09-11 14:59:26 +090029import android.os.Message;
30import android.util.Slog;
31import android.view.Display;
32import android.view.IWindow;
Daichi Hironodf5cf622017-09-11 14:59:26 +090033import android.view.SurfaceControl;
34import android.view.SurfaceSession;
35import android.view.View;
Adrian Roose99bc052017-11-20 17:55:31 +010036
Daichi Hirono3c6c95e2017-09-13 12:23:57 +090037import com.android.internal.util.Preconditions;
Adrian Roose99bc052017-11-20 17:55:31 +010038import com.android.server.wm.WindowManagerInternal.IDragDropCallback;
Garfield Tand427c622018-11-30 13:00:04 -080039
Daichi Hironobb28efb2017-11-21 15:11:01 +090040import java.util.concurrent.atomic.AtomicReference;
Daichi Hironodf5cf622017-09-11 14:59:26 +090041
42/**
43 * Managing drag and drop operations initiated by View#startDragAndDrop.
44 */
45class DragDropController {
46 private static final float DRAG_SHADOW_ALPHA_TRANSPARENT = .7071f;
47 private static final long DRAG_TIMEOUT_MS = 5000;
Daichi Hirono58e25e12017-10-25 15:48:08 +090048
49 // Messages for Handler.
Daichi Hironofabca092017-12-19 15:02:50 +090050 static final int MSG_DRAG_END_TIMEOUT = 0;
51 static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 1;
52 static final int MSG_ANIMATION_END = 2;
Daichi Hirono58e25e12017-10-25 15:48:08 +090053
Daichi Hirono3bae0b02017-10-27 13:05:13 +090054 /**
55 * Drag state per operation.
Daichi Hirono7a5d0072017-10-30 10:07:24 +090056 * Needs a lock of {@code WindowManagerService#mWindowMap} to read this. Needs both locks of
57 * {@code mWriteLock} and {@code WindowManagerService#mWindowMap} to update this.
Daichi Hirono3bae0b02017-10-27 13:05:13 +090058 * The variable is cleared by {@code #onDragStateClosedLocked} which is invoked by DragState
59 * itself, thus the variable can be null after calling DragState's methods.
60 */
Daichi Hirono768012e2017-10-30 10:05:37 +090061 private DragState mDragState;
Daichi Hirono76a26aa2017-09-11 15:13:38 +090062
Daichi Hirono58e25e12017-10-25 15:48:08 +090063 private WindowManagerService mService;
64 private final Handler mHandler;
Daichi Hirono3c6c95e2017-09-13 12:23:57 +090065
Daichi Hirono7a5d0072017-10-30 10:07:24 +090066 /**
Daichi Hirono3c6c95e2017-09-13 12:23:57 +090067 * Callback which is used to sync drag state with the vendor-specific code.
68 */
Daichi Hironobb28efb2017-11-21 15:11:01 +090069 @NonNull private AtomicReference<IDragDropCallback> mCallback = new AtomicReference<>(
70 new IDragDropCallback() {});
Daichi Hirono3c6c95e2017-09-13 12:23:57 +090071
Daichi Hirono76a26aa2017-09-11 15:13:38 +090072 boolean dragDropActiveLocked() {
Garfield Tand427c622018-11-30 13:00:04 -080073 return mDragState != null && !mDragState.isClosing();
Daichi Hirono76a26aa2017-09-11 15:13:38 +090074 }
Daichi Hironodf5cf622017-09-11 14:59:26 +090075
Robert Carre92c80c2018-08-14 15:38:44 -070076 void showInputSurface(SurfaceControl.Transaction t, int displayId) {
77 mDragState.showInputSurface(t, displayId);
78 }
79
80 void hideInputSurface(SurfaceControl.Transaction t, int displayId) {
81 if (mDragState != null) {
82 // TODO: Are we guaranteed to get here?
83 mDragState.hideInputSurface(t, displayId);
84 }
Daichi Hirono768012e2017-10-30 10:05:37 +090085 }
86
Daichi Hirono3c6c95e2017-09-13 12:23:57 +090087 void registerCallback(IDragDropCallback callback) {
88 Preconditions.checkNotNull(callback);
Daichi Hironobb28efb2017-11-21 15:11:01 +090089 mCallback.set(callback);
Daichi Hirono3c6c95e2017-09-13 12:23:57 +090090 }
91
Daichi Hirono58e25e12017-10-25 15:48:08 +090092 DragDropController(WindowManagerService service, Looper looper) {
93 mService = service;
94 mHandler = new DragHandler(service, looper);
95 }
96
Daichi Hirono768012e2017-10-30 10:05:37 +090097 void sendDragStartedIfNeededLocked(WindowState window) {
98 mDragState.sendDragStartedIfNeededLocked(window);
99 }
100
Daichi Hironofabca092017-12-19 15:02:50 +0900101 IBinder performDrag(SurfaceSession session, int callerPid, int callerUid, IWindow window,
102 int flags, SurfaceControl surface, int touchSource, float touchX, float touchY,
103 float thumbCenterX, float thumbCenterY, ClipData data) {
Daichi Hironodf5cf622017-09-11 14:59:26 +0900104 if (DEBUG_DRAG) {
Daichi Hironofabca092017-12-19 15:02:50 +0900105 Slog.d(TAG_WM, "perform drag: win=" + window + " surface=" + surface + " flags=" +
106 Integer.toHexString(flags) + " data=" + data);
Daichi Hironodf5cf622017-09-11 14:59:26 +0900107 }
108
Daichi Hironofabca092017-12-19 15:02:50 +0900109 final IBinder dragToken = new Binder();
Daichi Hirono663e9a72017-11-10 13:51:02 +0900110 final boolean callbackResult = mCallback.get().prePerformDrag(window, dragToken,
111 touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
Daichi Hironobb28efb2017-11-21 15:11:01 +0900112 try {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700113 synchronized (mService.mGlobalLock) {
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900114 try {
Daichi Hirono663e9a72017-11-10 13:51:02 +0900115 if (!callbackResult) {
Daichi Hironofabca092017-12-19 15:02:50 +0900116 Slog.w(TAG_WM, "IDragDropCallback rejects the performDrag request");
117 return null;
Daichi Hirono663e9a72017-11-10 13:51:02 +0900118 }
119
Daichi Hironofabca092017-12-19 15:02:50 +0900120 if (dragDropActiveLocked()) {
121 Slog.w(TAG_WM, "Drag already in progress");
122 return null;
123 }
Daichi Hirono663e9a72017-11-10 13:51:02 +0900124
125 final WindowState callingWin = mService.windowForClientLocked(
126 null, window, false);
127 if (callingWin == null) {
128 Slog.w(TAG_WM, "Bad requesting window " + window);
Daichi Hironofabca092017-12-19 15:02:50 +0900129 return null; // !!! TODO: throw here?
Daichi Hirono663e9a72017-11-10 13:51:02 +0900130 }
131
132 // !!! TODO: if input is not still focused on the initiating window, fail
133 // the drag initiation (e.g. an alarm window popped up just as the application
134 // called performDrag()
135
136 // !!! TODO: extract the current touch (x, y) in screen coordinates. That
137 // will let us eliminate the (touchX,touchY) parameters from the API.
138
139 // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
140 // the actual drag event dispatch stuff in the dragstate
141
Daichi Hironofabca092017-12-19 15:02:50 +0900142 // !!! TODO(multi-display): support other displays
143
Daichi Hirono663e9a72017-11-10 13:51:02 +0900144 final DisplayContent displayContent = callingWin.getDisplayContent();
145 if (displayContent == null) {
146 Slog.w(TAG_WM, "display content is null");
Daichi Hironofabca092017-12-19 15:02:50 +0900147 return null;
Daichi Hirono663e9a72017-11-10 13:51:02 +0900148 }
149
Daichi Hironofabca092017-12-19 15:02:50 +0900150 final float alpha = (flags & View.DRAG_FLAG_OPAQUE) == 0 ?
151 DRAG_SHADOW_ALPHA_TRANSPARENT : 1;
152 final IBinder winBinder = window.asBinder();
153 IBinder token = new Binder();
154 mDragState = new DragState(mService, this, token, surface, flags, winBinder);
155 surface = null;
156 mDragState.mPid = callerPid;
157 mDragState.mUid = callerUid;
158 mDragState.mOriginalAlpha = alpha;
159 mDragState.mToken = dragToken;
Riddle Hsu654a6f92018-07-13 22:59:36 +0800160 mDragState.mDisplayContent = displayContent;
Daichi Hironofabca092017-12-19 15:02:50 +0900161
Daichi Hirono663e9a72017-11-10 13:51:02 +0900162 final Display display = displayContent.getDisplay();
Daichi Hirono4a545172018-02-01 10:59:48 +0900163 if (!mCallback.get().registerInputChannel(
164 mDragState, display, mService.mInputManager,
165 callingWin.mInputChannel)) {
Daichi Hirono663e9a72017-11-10 13:51:02 +0900166 Slog.e(TAG_WM, "Unable to transfer touch focus");
Daichi Hironofabca092017-12-19 15:02:50 +0900167 return null;
Daichi Hirono663e9a72017-11-10 13:51:02 +0900168 }
169
Daichi Hirono663e9a72017-11-10 13:51:02 +0900170 mDragState.mData = data;
171 mDragState.broadcastDragStartedLocked(touchX, touchY);
172 mDragState.overridePointerIconLocked(touchSource);
173 // remember the thumb offsets for later
174 mDragState.mThumbOffsetX = thumbCenterX;
175 mDragState.mThumbOffsetY = thumbCenterY;
176
177 // Make the surface visible at the proper location
178 final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
179 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
Daichi Hironoa1fb9be2017-12-18 17:02:54 +0900180
181 final SurfaceControl.Transaction transaction =
182 callingWin.getPendingTransaction();
183 transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
184 transaction.setPosition(
185 surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY);
186 transaction.show(surfaceControl);
187 displayContent.reparentToOverlay(transaction, surfaceControl);
188 callingWin.scheduleAnimation();
189
190 if (SHOW_LIGHT_TRANSACTIONS) {
191 Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
Daichi Hirono663e9a72017-11-10 13:51:02 +0900192 }
193
194 mDragState.notifyLocationLocked(touchX, touchY);
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900195 } finally {
Daichi Hironoa1fb9be2017-12-18 17:02:54 +0900196 if (surface != null) {
197 surface.release();
198 }
Daichi Hirono663e9a72017-11-10 13:51:02 +0900199 if (mDragState != null && !mDragState.isInProgress()) {
200 mDragState.closeLocked();
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900201 }
202 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900203 }
Daichi Hironofabca092017-12-19 15:02:50 +0900204 return dragToken; // success!
Daichi Hironobb28efb2017-11-21 15:11:01 +0900205 } finally {
206 mCallback.get().postPerformDrag();
Daichi Hironodf5cf622017-09-11 14:59:26 +0900207 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900208 }
209
Daichi Hirono58e25e12017-10-25 15:48:08 +0900210 void reportDropResult(IWindow window, boolean consumed) {
Daichi Hironodf5cf622017-09-11 14:59:26 +0900211 IBinder token = window.asBinder();
212 if (DEBUG_DRAG) {
213 Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token);
214 }
215
Daichi Hironobb28efb2017-11-21 15:11:01 +0900216 mCallback.get().preReportDropResult(window, consumed);
217 try {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700218 synchronized (mService.mGlobalLock) {
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900219 if (mDragState == null) {
220 // Most likely the drop recipient ANRed and we ended the drag
221 // out from under it. Log the issue and move on.
222 Slog.w(TAG_WM, "Drop result given but no drag in progress");
223 return;
224 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900225
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900226 if (mDragState.mToken != token) {
227 // We're in a drag, but the wrong window has responded.
228 Slog.w(TAG_WM, "Invalid drop-result claim by " + window);
229 throw new IllegalStateException("reportDropResult() by non-recipient");
230 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900231
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900232 // The right window has responded, even if it's no longer around,
233 // so be sure to halt the timeout even if the later WindowState
234 // lookup fails.
235 mHandler.removeMessages(MSG_DRAG_END_TIMEOUT, window.asBinder());
236 WindowState callingWin = mService.windowForClientLocked(null, window, false);
237 if (callingWin == null) {
238 Slog.w(TAG_WM, "Bad result-reporting window " + window);
239 return; // !!! TODO: throw here?
240 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900241
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900242 mDragState.mDragResult = consumed;
243 mDragState.endDragLocked();
244 }
Daichi Hironobb28efb2017-11-21 15:11:01 +0900245 } finally {
246 mCallback.get().postReportDropResult();
Daichi Hironodf5cf622017-09-11 14:59:26 +0900247 }
248 }
249
Daichi Hirono58e25e12017-10-25 15:48:08 +0900250 void cancelDragAndDrop(IBinder dragToken) {
Daichi Hironodf5cf622017-09-11 14:59:26 +0900251 if (DEBUG_DRAG) {
252 Slog.d(TAG_WM, "cancelDragAndDrop");
253 }
254
Daichi Hironobb28efb2017-11-21 15:11:01 +0900255 mCallback.get().preCancelDragAndDrop(dragToken);
256 try {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700257 synchronized (mService.mGlobalLock) {
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900258 if (mDragState == null) {
259 Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
260 throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()");
261 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900262
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900263 if (mDragState.mToken != dragToken) {
264 Slog.w(TAG_WM,
265 "cancelDragAndDrop() does not match prepareDrag()");
266 throw new IllegalStateException(
267 "cancelDragAndDrop() does not match prepareDrag()");
268 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900269
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900270 mDragState.mDragResult = false;
271 mDragState.cancelDragLocked();
272 }
Daichi Hironobb28efb2017-11-21 15:11:01 +0900273 } finally {
274 mCallback.get().postCancelDragAndDrop();
Daichi Hironodf5cf622017-09-11 14:59:26 +0900275 }
276 }
277
Daichi Hirono768012e2017-10-30 10:05:37 +0900278 /**
279 * Handles motion events.
280 * @param keepHandling Whether if the drag operation is continuing or this is the last motion
281 * event.
282 * @param newX X coordinate value in dp in the screen coordinate
283 * @param newY Y coordinate value in dp in the screen coordinate
284 */
285 void handleMotionEvent(boolean keepHandling, float newX, float newY) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700286 synchronized (mService.mGlobalLock) {
Daichi Hironobb28efb2017-11-21 15:11:01 +0900287 if (!dragDropActiveLocked()) {
288 // The drag has ended but the clean-up message has not been processed by
289 // window manager. Drop events that occur after this until window manager
290 // has a chance to clean-up the input handle.
291 return;
292 }
Daichi Hirono768012e2017-10-30 10:05:37 +0900293
Daichi Hironobb28efb2017-11-21 15:11:01 +0900294 if (keepHandling) {
295 mDragState.notifyMoveLocked(newX, newY);
296 } else {
297 mDragState.notifyDropLocked(newX, newY);
Daichi Hirono768012e2017-10-30 10:05:37 +0900298 }
299 }
300 }
301
Daichi Hironodf5cf622017-09-11 14:59:26 +0900302 void dragRecipientEntered(IWindow window) {
303 if (DEBUG_DRAG) {
304 Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder());
305 }
306 }
307
308 void dragRecipientExited(IWindow window) {
309 if (DEBUG_DRAG) {
310 Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder());
311 }
312 }
313
Daichi Hirono58e25e12017-10-25 15:48:08 +0900314 /**
315 * Sends a message to the Handler managed by DragDropController.
316 */
317 void sendHandlerMessage(int what, Object arg) {
318 mHandler.obtainMessage(what, arg).sendToTarget();
319 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900320
Daichi Hirono58e25e12017-10-25 15:48:08 +0900321 /**
322 * Sends a timeout message to the Handler managed by DragDropController.
323 */
324 void sendTimeoutMessage(int what, Object arg) {
325 mHandler.removeMessages(what, arg);
326 final Message msg = mHandler.obtainMessage(what, arg);
327 mHandler.sendMessageDelayed(msg, DRAG_TIMEOUT_MS);
328 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900329
Daichi Hirono3bae0b02017-10-27 13:05:13 +0900330 /**
331 * Notifies the current drag state is closed.
332 */
333 void onDragStateClosedLocked(DragState dragState) {
334 if (mDragState != dragState) {
335 Slog.wtf(TAG_WM, "Unknown drag state is closed");
336 return;
337 }
338 mDragState = null;
339 }
340
Daichi Hirono58e25e12017-10-25 15:48:08 +0900341 private class DragHandler extends Handler {
342 /**
343 * Lock for window manager.
344 */
345 private final WindowManagerService mService;
346
347 DragHandler(WindowManagerService service, Looper looper) {
348 super(looper);
349 mService = service;
350 }
351
352 @Override
353 public void handleMessage(Message msg) {
354 switch (msg.what) {
Daichi Hirono58e25e12017-10-25 15:48:08 +0900355 case MSG_DRAG_END_TIMEOUT: {
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900356 final IBinder win = (IBinder) msg.obj;
Daichi Hirono58e25e12017-10-25 15:48:08 +0900357 if (DEBUG_DRAG) {
358 Slog.w(TAG_WM, "Timeout ending drag to win " + win);
359 }
Daichi Hironobb28efb2017-11-21 15:11:01 +0900360
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700361 synchronized (mService.mGlobalLock) {
Daichi Hironobb28efb2017-11-21 15:11:01 +0900362 // !!! TODO: ANR the drag-receiving app
363 if (mDragState != null) {
364 mDragState.mDragResult = false;
365 mDragState.endDragLocked();
Daichi Hirono58e25e12017-10-25 15:48:08 +0900366 }
367 }
368 break;
369 }
370
371 case MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT: {
372 if (DEBUG_DRAG)
373 Slog.d(TAG_WM, "Drag ending; tearing down input channel");
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900374 final DragState.InputInterceptor interceptor =
375 (DragState.InputInterceptor) msg.obj;
376 if (interceptor == null) return;
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700377 synchronized (mService.mGlobalLock) {
Daichi Hirono7a5d0072017-10-30 10:07:24 +0900378 interceptor.tearDown();
Daichi Hirono58e25e12017-10-25 15:48:08 +0900379 }
380 break;
381 }
382
383 case MSG_ANIMATION_END: {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700384 synchronized (mService.mGlobalLock) {
Daichi Hironobb28efb2017-11-21 15:11:01 +0900385 if (mDragState == null) {
386 Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
387 "plyaing animation");
388 return;
Daichi Hirono58e25e12017-10-25 15:48:08 +0900389 }
Daichi Hironobb28efb2017-11-21 15:11:01 +0900390 mDragState.closeLocked();
Daichi Hirono58e25e12017-10-25 15:48:08 +0900391 }
392 break;
393 }
Daichi Hironodf5cf622017-09-11 14:59:26 +0900394 }
395 }
396 }
397}