blob: cdcb85720724e7d57e29483cae0cda355c46defb [file] [log] [blame]
Daichi Hirono34fb7312017-12-04 10:00:24 +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
19import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
20import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
21
22import android.annotation.Nullable;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070023import android.app.IActivityTaskManager;
Robert Carre92c80c2018-08-14 15:38:44 -070024import android.graphics.Point;
25import android.graphics.Rect;
Daichi Hironoce2f97a2017-11-30 16:44:15 +090026import android.os.Handler;
chaviwb5e316c2018-12-26 15:39:15 -080027import android.os.IBinder;
Daichi Hironoce2f97a2017-11-30 16:44:15 +090028import android.os.Looper;
Garfield Tan07544cd2018-09-12 16:16:54 -070029import android.os.RemoteException;
Daichi Hirono34fb7312017-12-04 10:00:24 +090030import android.util.Slog;
Robert Carre92c80c2018-08-14 15:38:44 -070031import android.view.Display;
Daichi Hirono34fb7312017-12-04 10:00:24 +090032import android.view.IWindow;
Garfield Tand427c622018-11-30 13:00:04 -080033import android.view.InputWindowHandle;
34import android.view.SurfaceControl;
Garfield Tan07544cd2018-09-12 16:16:54 -070035
Daichi Hirono34fb7312017-12-04 10:00:24 +090036import com.android.internal.annotations.GuardedBy;
37import com.android.server.input.InputManagerService;
Daichi Hirono34fb7312017-12-04 10:00:24 +090038
39/**
40 * Controller for task positioning by drag.
41 */
42class TaskPositioningController {
43 private final WindowManagerService mService;
44 private final InputManagerService mInputManager;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070045 private final IActivityTaskManager mActivityManager;
Daichi Hironoce2f97a2017-11-30 16:44:15 +090046 private final Handler mHandler;
Robert Carre92c80c2018-08-14 15:38:44 -070047 private SurfaceControl mInputSurface;
48 private DisplayContent mPositioningDisplay;
Daichi Hirono34fb7312017-12-04 10:00:24 +090049
50 @GuardedBy("WindowManagerSerivce.mWindowMap")
51 private @Nullable TaskPositioner mTaskPositioner;
52
Robert Carre92c80c2018-08-14 15:38:44 -070053 private final Rect mTmpClipRect = new Rect();
chaviwb5e316c2018-12-26 15:39:15 -080054 private IBinder mTransferTouchFromToken;
Robert Carre92c80c2018-08-14 15:38:44 -070055
Daichi Hirono34fb7312017-12-04 10:00:24 +090056 boolean isPositioningLocked() {
57 return mTaskPositioner != null;
58 }
59
60 InputWindowHandle getDragWindowHandleLocked() {
61 return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
62 }
63
64 TaskPositioningController(WindowManagerService service, InputManagerService inputManager,
Arthur Hung95b38a92018-07-20 18:56:12 +080065 IActivityTaskManager activityManager, Looper looper) {
Daichi Hirono34fb7312017-12-04 10:00:24 +090066 mService = service;
Daichi Hirono34fb7312017-12-04 10:00:24 +090067 mInputManager = inputManager;
68 mActivityManager = activityManager;
Daichi Hironoce2f97a2017-11-30 16:44:15 +090069 mHandler = new Handler(looper);
Daichi Hirono34fb7312017-12-04 10:00:24 +090070 }
71
Robert Carre92c80c2018-08-14 15:38:44 -070072 void hideInputSurface(SurfaceControl.Transaction t, int displayId) {
73 if (mPositioningDisplay != null && mPositioningDisplay.getDisplayId() == displayId
74 && mInputSurface != null) {
75 t.hide(mInputSurface);
76 }
77 }
78
79 void showInputSurface(SurfaceControl.Transaction t, int displayId) {
80 if (mPositioningDisplay == null || mPositioningDisplay.getDisplayId() != displayId) {
81 return;
82 }
83 final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
84 if (mInputSurface == null) {
85 mInputSurface = mService.makeSurfaceBuilder(dc.getSession())
Chavi Weingarten6ef9cc62019-02-07 16:28:45 +000086 .setContainerLayer()
Vishnu Naire86bd982018-11-28 13:23:17 -080087 .setName("Drag and Drop Input Consumer").build();
Robert Carre92c80c2018-08-14 15:38:44 -070088 }
89
90 final InputWindowHandle h = getDragWindowHandleLocked();
91 if (h == null) {
92 Slog.w(TAG_WM, "Drag is in progress but there is no "
93 + "drag window handle.");
94 return;
95 }
96
97 t.show(mInputSurface);
98 t.setInputWindowInfo(mInputSurface, h);
99 t.setLayer(mInputSurface, Integer.MAX_VALUE);
100
101 final Display display = dc.getDisplay();
102 final Point p = new Point();
103 display.getRealSize(p);
104
105 mTmpClipRect.set(0, 0, p.x, p.y);
106 t.setWindowCrop(mInputSurface, mTmpClipRect);
chaviwb5e316c2018-12-26 15:39:15 -0800107 t.transferTouchFocus(mTransferTouchFromToken, h.token);
108 mTransferTouchFromToken = null;
Robert Carre92c80c2018-08-14 15:38:44 -0700109 }
110
Daichi Hirono34fb7312017-12-04 10:00:24 +0900111 boolean startMovingTask(IWindow window, float startX, float startY) {
112 WindowState win = null;
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700113 synchronized (mService.mGlobalLock) {
Daichi Hirono34fb7312017-12-04 10:00:24 +0900114 win = mService.windowForClientLocked(null, window, false);
115 // win shouldn't be null here, pass it down to startPositioningLocked
116 // to get warning if it's null.
117 if (!startPositioningLocked(
118 win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
119 return false;
120 }
121 }
122 try {
123 mActivityManager.setFocusedTask(win.getTask().mTaskId);
124 } catch(RemoteException e) {}
125 return true;
126 }
127
128 void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
Daichi Hironoce2f97a2017-11-30 16:44:15 +0900129 mHandler.post(() -> {
130 int taskId = -1;
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700131 synchronized (mService.mGlobalLock) {
Daichi Hironoce2f97a2017-11-30 16:44:15 +0900132 final Task task = displayContent.findTaskForResizePoint(x, y);
133 if (task != null) {
134 if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
135 task.preserveOrientationOnResize(), x, y)) {
136 return;
137 }
138 taskId = task.mTaskId;
139 } else {
Garfield Tan4f71c5a2018-10-10 10:12:02 -0700140 taskId = displayContent.taskForTapOutside(x, y);
Daichi Hirono34fb7312017-12-04 10:00:24 +0900141 }
Daichi Hirono34fb7312017-12-04 10:00:24 +0900142 }
Daichi Hironoce2f97a2017-11-30 16:44:15 +0900143 if (taskId >= 0) {
144 try {
145 mActivityManager.setFocusedTask(taskId);
146 } catch (RemoteException e) {
147 }
148 }
149 });
Daichi Hirono34fb7312017-12-04 10:00:24 +0900150 }
151
152 private boolean startPositioningLocked(WindowState win, boolean resize,
153 boolean preserveOrientation, float startX, float startY) {
154 if (DEBUG_TASK_POSITIONING)
155 Slog.d(TAG_WM, "startPositioningLocked: "
156 + "win=" + win + ", resize=" + resize + ", preserveOrientation="
157 + preserveOrientation + ", {" + startX + ", " + startY + "}");
158
159 if (win == null || win.getAppToken() == null) {
160 Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
161 return false;
162 }
163 if (win.mInputChannel == null) {
164 Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
165 + " probably being removed");
166 return false;
167 }
168
169 final DisplayContent displayContent = win.getDisplayContent();
170 if (displayContent == null) {
171 Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
172 return false;
173 }
Robert Carre92c80c2018-08-14 15:38:44 -0700174 mPositioningDisplay = displayContent;
Daichi Hirono34fb7312017-12-04 10:00:24 +0900175
Garfield Tan6caf1d8c2018-01-18 12:37:50 -0800176 mTaskPositioner = TaskPositioner.create(mService);
Daichi Hirono34fb7312017-12-04 10:00:24 +0900177
178 // We need to grab the touch focus so that the touch events during the
179 // resizing/scrolling are not sent to the app. 'win' is the main window
180 // of the app, it may not have focus since there might be other windows
181 // on top (eg. a dialog window).
182 WindowState transferFocusFromWin = win;
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800183 if (displayContent.mCurrentFocus != null && displayContent.mCurrentFocus != win
184 && displayContent.mCurrentFocus.mAppToken == win.mAppToken) {
185 transferFocusFromWin = displayContent.mCurrentFocus;
Daichi Hirono34fb7312017-12-04 10:00:24 +0900186 }
chaviwb5e316c2018-12-26 15:39:15 -0800187 mTransferTouchFromToken = transferFocusFromWin.mInputChannel.getToken();
188 mTaskPositioner.register(displayContent);
Daichi Hirono34fb7312017-12-04 10:00:24 +0900189
190 mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
191 return true;
192 }
193
Daichi Hironoce2f97a2017-11-30 16:44:15 +0900194 void finishTaskPositioning() {
195 mHandler.post(() -> {
196 if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning");
Daichi Hirono34fb7312017-12-04 10:00:24 +0900197
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700198 synchronized (mService.mGlobalLock) {
Garfield Tand427c622018-11-30 13:00:04 -0800199 cleanUpTaskPositioner();
Robert Carre92c80c2018-08-14 15:38:44 -0700200 mPositioningDisplay = null;
Daichi Hirono34fb7312017-12-04 10:00:24 +0900201 }
Daichi Hironoce2f97a2017-11-30 16:44:15 +0900202 });
Daichi Hirono34fb7312017-12-04 10:00:24 +0900203 }
Garfield Tand427c622018-11-30 13:00:04 -0800204
205 private void cleanUpTaskPositioner() {
206 final TaskPositioner positioner = mTaskPositioner;
207 if (positioner == null) {
208 return;
209 }
210
211 // We need to assign task positioner to null first to indicate that we're finishing task
212 // positioning.
213 mTaskPositioner = null;
214 positioner.unregister();
215 }
Daichi Hirono34fb7312017-12-04 10:00:24 +0900216}