blob: b5892b9b4dc6472ba780a537f2a3e6a7efe3e031 [file] [log] [blame]
Chong Zhang8e89b312015-09-09 15:09:30 -07001/*
2 * Copyright (C) 2015 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
Wale Ogunwale65ebd952018-04-25 15:41:44 -070019import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
20import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
Wale Ogunwalecad05a02015-09-25 10:41:44 -070021import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
Garfield Tan07544cd2018-09-12 16:16:54 -070022
Ben Lin2e306af2020-02-03 14:23:57 -080023import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
24import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT;
25import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE;
26import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT;
27import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP;
Garfield Tan07544cd2018-09-12 16:16:54 -070028import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
Adrian Roosb125e0b2019-10-02 14:55:14 +020029import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080030import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080031import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
32import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -070033import static com.android.server.wm.WindowManagerService.dipToPixel;
Wale Ogunwale231b06e2015-09-16 12:03:09 -070034import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
35import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
Chong Zhang8e89b312015-09-09 15:09:30 -070036
Yongjin Kwon9c5f0aa2019-11-06 17:36:24 +090037import android.annotation.NonNull;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070038import android.app.IActivityTaskManager;
Chong Zhang8e89b312015-09-09 15:09:30 -070039import android.graphics.Point;
40import android.graphics.Rect;
Robert Carr0bcbe642018-10-11 19:07:43 -070041import android.os.Binder;
yj81.kwon79c97672019-04-16 19:44:48 -070042import android.os.IBinder;
Chong Zhang8e89b312015-09-09 15:09:30 -070043import android.os.Looper;
44import android.os.Process;
45import android.os.RemoteException;
Wale Ogunwalecad05a02015-09-25 10:41:44 -070046import android.os.Trace;
Chong Zhang8e89b312015-09-09 15:09:30 -070047import android.util.DisplayMetrics;
48import android.util.Slog;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080049import android.view.BatchedInputEventReceiver;
Wale Ogunwale4f52bc62015-09-24 13:47:31 -070050import android.view.Choreographer;
Chong Zhang8e89b312015-09-09 15:09:30 -070051import android.view.Display;
Evan Rosky0d654cb2019-02-26 10:59:10 -080052import android.view.InputApplicationHandle;
Chong Zhang8e89b312015-09-09 15:09:30 -070053import android.view.InputChannel;
54import android.view.InputDevice;
55import android.view.InputEvent;
Evan Rosky0d654cb2019-02-26 10:59:10 -080056import android.view.InputWindowHandle;
Chong Zhang8e89b312015-09-09 15:09:30 -070057import android.view.MotionEvent;
Arthur Hungb62e5002019-08-29 12:28:07 +080058import android.view.SurfaceControl;
Chong Zhang8e89b312015-09-09 15:09:30 -070059import android.view.WindowManager;
60
skuhne@google.com322347b2016-12-02 12:54:03 -080061import com.android.internal.annotations.VisibleForTesting;
Ben Lin2e306af2020-02-03 14:23:57 -080062import com.android.internal.policy.TaskResizingAlgorithm;
63import com.android.internal.policy.TaskResizingAlgorithm.CtrlType;
Adrian Roosb125e0b2019-10-02 14:55:14 +020064import com.android.server.protolog.common.ProtoLog;
Wale Ogunwale228d4042015-09-13 10:17:34 -070065
yj81.kwon79c97672019-04-16 19:44:48 -070066class TaskPositioner implements IBinder.DeathRecipient {
skuhne@google.com322347b2016-12-02 12:54:03 -080067 private static final boolean DEBUG_ORIENTATION_VIOLATIONS = false;
Jorim Jaggibc5425c2016-03-01 13:51:16 +010068 private static final String TAG_LOCAL = "TaskPositioner";
69 private static final String TAG = TAG_WITH_CLASS_NAME ? TAG_LOCAL : TAG_WM;
Chong Zhang8e89b312015-09-09 15:09:30 -070070
Garfield Tan6caf1d8c2018-01-18 12:37:50 -080071 private static Factory sFactory;
72
Filip Gruszczynski64b6b442016-01-18 13:20:58 -080073 public static final float RESIZING_HINT_ALPHA = 0.5f;
74
75 public static final int RESIZING_HINT_DURATION_MS = 0;
76
Chong Zhang8e89b312015-09-09 15:09:30 -070077 private final WindowManagerService mService;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070078 private final IActivityTaskManager mActivityManager;
Chong Zhang8e89b312015-09-09 15:09:30 -070079 private WindowPositionerEventReceiver mInputEventReceiver;
Riddle Hsu654a6f92018-07-13 22:59:36 +080080 private DisplayContent mDisplayContent;
Chong Zhang8e89b312015-09-09 15:09:30 -070081 private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
Wale Ogunwale228d4042015-09-13 10:17:34 -070082 private Rect mTmpRect = new Rect();
Wale Ogunwaleb8051b82015-09-17 15:41:52 -070083 private int mMinVisibleWidth;
84 private int mMinVisibleHeight;
Chong Zhang8e89b312015-09-09 15:09:30 -070085
Charles Chen2cb5a0f2019-03-22 20:58:00 +080086 @VisibleForTesting
87 Task mTask;
Yongjin Kwon9c5f0aa2019-11-06 17:36:24 +090088 WindowState mWindow;
Chong Zhang09b21ef2015-09-14 10:20:21 -070089 private boolean mResizing;
skuhne@google.com322347b2016-12-02 12:54:03 -080090 private boolean mPreserveOrientation;
91 private boolean mStartOrientationWasLandscape;
Chong Zhang8e89b312015-09-09 15:09:30 -070092 private final Rect mWindowOriginalBounds = new Rect();
93 private final Rect mWindowDragBounds = new Rect();
skuhne@google.com322347b2016-12-02 12:54:03 -080094 private final Point mMaxVisibleSize = new Point();
Chong Zhang8e89b312015-09-09 15:09:30 -070095 private float mStartDragX;
96 private float mStartDragY;
97 @CtrlType
98 private int mCtrlType = CTRL_NONE;
yj81.kwon79c97672019-04-16 19:44:48 -070099 @VisibleForTesting
100 boolean mDragEnded;
yj81.kwon19585ff2019-04-23 18:53:57 -0700101 IBinder mClientCallback;
Chong Zhang8e89b312015-09-09 15:09:30 -0700102
103 InputChannel mServerChannel;
104 InputChannel mClientChannel;
105 InputApplicationHandle mDragApplicationHandle;
106 InputWindowHandle mDragWindowHandle;
107
Wale Ogunwale4f52bc62015-09-24 13:47:31 -0700108 private final class WindowPositionerEventReceiver extends BatchedInputEventReceiver {
109 public WindowPositionerEventReceiver(
110 InputChannel inputChannel, Looper looper, Choreographer choreographer) {
111 super(inputChannel, looper, choreographer);
Chong Zhang8e89b312015-09-09 15:09:30 -0700112 }
113
114 @Override
Siarhei Vishniakou85ddfff2018-01-31 16:49:36 -0800115 public void onInputEvent(InputEvent event) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700116 boolean handled = false;
Chong Zhang8e89b312015-09-09 15:09:30 -0700117 try {
Yunfan Chen54872c32019-11-14 19:41:47 -0800118 // All returns need to be in the try block to make sure the finishInputEvent is
119 // called correctly.
120 if (!(event instanceof MotionEvent)
121 || (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
122 return;
123 }
124 final MotionEvent motionEvent = (MotionEvent) event;
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700125 if (mDragEnded) {
126 // The drag has ended but the clean-up message has not been processed by
127 // window manager. Drop events that occur after this until window manager
128 // has a chance to clean-up the input handle.
129 handled = true;
130 return;
131 }
132
Chong Zhang8e89b312015-09-09 15:09:30 -0700133 final float newX = motionEvent.getRawX();
134 final float newY = motionEvent.getRawY();
135
136 switch (motionEvent.getAction()) {
137 case MotionEvent.ACTION_DOWN: {
138 if (DEBUG_TASK_POSITIONING) {
139 Slog.w(TAG, "ACTION_DOWN @ {" + newX + ", " + newY + "}");
140 }
141 } break;
142
143 case MotionEvent.ACTION_MOVE: {
144 if (DEBUG_TASK_POSITIONING){
145 Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}");
146 }
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700147 synchronized (mService.mGlobalLock) {
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700148 mDragEnded = notifyMoveLocked(newX, newY);
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800149 mTask.getDimBounds(mTmpRect);
Chong Zhang8e89b312015-09-09 15:09:30 -0700150 }
Wale Ogunwale04ad7b12015-10-02 12:43:27 -0700151 if (!mTmpRect.equals(mWindowDragBounds)) {
152 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
153 "wm.TaskPositioner.resizeTask");
154 try {
Daichi Hirono67f2f4b2018-05-25 16:07:30 +0900155 mActivityManager.resizeTask(
Wale Ogunwale04ad7b12015-10-02 12:43:27 -0700156 mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
157 } catch (RemoteException e) {
158 }
159 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
160 }
Chong Zhang8e89b312015-09-09 15:09:30 -0700161 } break;
162
163 case MotionEvent.ACTION_UP: {
164 if (DEBUG_TASK_POSITIONING) {
165 Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}");
166 }
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700167 mDragEnded = true;
Chong Zhang8e89b312015-09-09 15:09:30 -0700168 } break;
169
170 case MotionEvent.ACTION_CANCEL: {
171 if (DEBUG_TASK_POSITIONING) {
172 Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}");
173 }
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700174 mDragEnded = true;
Chong Zhang8e89b312015-09-09 15:09:30 -0700175 } break;
176 }
177
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700178 if (mDragEnded) {
Wale Ogunwale04ad7b12015-10-02 12:43:27 -0700179 final boolean wasResizing = mResizing;
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700180 synchronized (mService.mGlobalLock) {
Chong Zhang3005e752015-09-18 18:46:28 -0700181 endDragLocked();
Vladislav Kaznacheev824bc5d2016-04-22 17:48:35 -0700182 mTask.getDimBounds(mTmpRect);
Chong Zhang3005e752015-09-18 18:46:28 -0700183 }
Chong Zhang09b21ef2015-09-14 10:20:21 -0700184 try {
Vladislav Kaznacheev824bc5d2016-04-22 17:48:35 -0700185 if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
Chong Zhang3005e752015-09-18 18:46:28 -0700186 // We were using fullscreen surface during resizing. Request
187 // resizeTask() one last time to restore surface to window size.
Daichi Hirono67f2f4b2018-05-25 16:07:30 +0900188 mActivityManager.resizeTask(
Chong Zhang6de2ae82015-09-30 18:25:21 -0700189 mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
Chong Zhang3005e752015-09-18 18:46:28 -0700190 }
Chong Zhang09b21ef2015-09-14 10:20:21 -0700191 } catch(RemoteException e) {}
Chong Zhang3005e752015-09-18 18:46:28 -0700192
Chong Zhang8e89b312015-09-09 15:09:30 -0700193 // Post back to WM to handle clean-ups. We still need the input
194 // event handler for the last finishInputEvent()!
Daichi Hironoce2f97a2017-11-30 16:44:15 +0900195 mService.mTaskPositioningController.finishTaskPositioning();
Chong Zhang8e89b312015-09-09 15:09:30 -0700196 }
197 handled = true;
198 } catch (Exception e) {
199 Slog.e(TAG, "Exception caught by drag handleMotion", e);
200 } finally {
201 finishInputEvent(event, handled);
202 }
203 }
204 }
205
Daichi Hirono67f2f4b2018-05-25 16:07:30 +0900206 @VisibleForTesting
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700207 TaskPositioner(WindowManagerService service, IActivityTaskManager activityManager) {
Daichi Hirono67f2f4b2018-05-25 16:07:30 +0900208 mService = service;
209 mActivityManager = activityManager;
210 }
211
Garfield Tan6caf1d8c2018-01-18 12:37:50 -0800212 /** Use {@link #create(WindowManagerService)} instead **/
Chong Zhang8e89b312015-09-09 15:09:30 -0700213 TaskPositioner(WindowManagerService service) {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700214 this(service, service.mActivityTaskManager);
Chong Zhang8e89b312015-09-09 15:09:30 -0700215 }
216
skuhne@google.com322347b2016-12-02 12:54:03 -0800217 @VisibleForTesting
218 Rect getWindowDragBounds() {
219 return mWindowDragBounds;
220 }
221
Chong Zhang8e89b312015-09-09 15:09:30 -0700222 /**
Garfield Tan07544cd2018-09-12 16:16:54 -0700223 * @param displayContent The Display that the window being dragged is on.
Yongjin Kwon9c5f0aa2019-11-06 17:36:24 +0900224 * @param win The window which will be dragged.
Chong Zhang8e89b312015-09-09 15:09:30 -0700225 */
Yongjin Kwon9c5f0aa2019-11-06 17:36:24 +0900226 void register(DisplayContent displayContent, @NonNull WindowState win) {
Robert Carrb1579c82017-09-05 14:54:47 -0700227 final Display display = displayContent.getDisplay();
228
Chong Zhang8e89b312015-09-09 15:09:30 -0700229 if (DEBUG_TASK_POSITIONING) {
230 Slog.d(TAG, "Registering task positioner");
231 }
232
233 if (mClientChannel != null) {
234 Slog.e(TAG, "Task positioner already registered");
235 return;
236 }
237
Riddle Hsu654a6f92018-07-13 22:59:36 +0800238 mDisplayContent = displayContent;
239 display.getMetrics(mDisplayMetrics);
Chong Zhang8e89b312015-09-09 15:09:30 -0700240 final InputChannel[] channels = InputChannel.openInputChannelPair(TAG);
241 mServerChannel = channels[0];
242 mClientChannel = channels[1];
Vishnu Nair18782162019-10-08 14:57:16 -0700243 mService.mInputManager.registerInputChannel(mServerChannel);
Chong Zhang8e89b312015-09-09 15:09:30 -0700244
Wale Ogunwale4f52bc62015-09-24 13:47:31 -0700245 mInputEventReceiver = new WindowPositionerEventReceiver(
Jorim Jaggied7993b2017-03-28 18:50:01 +0100246 mClientChannel, mService.mAnimationHandler.getLooper(),
247 mService.mAnimator.getChoreographer());
Chong Zhang8e89b312015-09-09 15:09:30 -0700248
Robert Carr0bcbe642018-10-11 19:07:43 -0700249 mDragApplicationHandle = new InputApplicationHandle(new Binder());
Chong Zhang8e89b312015-09-09 15:09:30 -0700250 mDragApplicationHandle.name = TAG;
251 mDragApplicationHandle.dispatchingTimeoutNanos =
252 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
253
Vishnu Nair18782162019-10-08 14:57:16 -0700254 mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, display.getDisplayId());
Chong Zhang8e89b312015-09-09 15:09:30 -0700255 mDragWindowHandle.name = TAG;
Robert Carreadae822018-10-11 19:07:03 -0700256 mDragWindowHandle.token = mServerChannel.getToken();
Chong Zhang8e89b312015-09-09 15:09:30 -0700257 mDragWindowHandle.layoutParamsFlags = 0;
258 mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
259 mDragWindowHandle.dispatchingTimeoutNanos =
260 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
261 mDragWindowHandle.visible = true;
262 mDragWindowHandle.canReceiveKeys = false;
263 mDragWindowHandle.hasFocus = true;
264 mDragWindowHandle.hasWallpaper = false;
265 mDragWindowHandle.paused = false;
266 mDragWindowHandle.ownerPid = Process.myPid();
267 mDragWindowHandle.ownerUid = Process.myUid();
268 mDragWindowHandle.inputFeatures = 0;
269 mDragWindowHandle.scaleFactor = 1.0f;
270
271 // The drag window cannot receive new touches.
272 mDragWindowHandle.touchableRegion.setEmpty();
273
274 // The drag window covers the entire display
275 mDragWindowHandle.frameLeft = 0;
276 mDragWindowHandle.frameTop = 0;
277 final Point p = new Point();
Riddle Hsu654a6f92018-07-13 22:59:36 +0800278 display.getRealSize(p);
Chong Zhang8e89b312015-09-09 15:09:30 -0700279 mDragWindowHandle.frameRight = p.x;
280 mDragWindowHandle.frameBottom = p.y;
281
282 // Pause rotations before a drag.
Adrian Roosb125e0b2019-10-02 14:55:14 +0200283 ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position");
Riddle Hsuccf09402019-08-13 00:33:06 +0800284 mDisplayContent.getDisplayRotation().pause();
Wale Ogunwale228d4042015-09-13 10:17:34 -0700285
Garfield Tan07544cd2018-09-12 16:16:54 -0700286 // Notify InputMonitor to take mDragWindowHandle.
Arthur Hungb62e5002019-08-29 12:28:07 +0800287 mDisplayContent.getInputMonitor().updateInputWindowsImmediately();
288 new SurfaceControl.Transaction().syncInputWindows().apply(true);
Garfield Tan07544cd2018-09-12 16:16:54 -0700289
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -0700290 mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
291 mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
Riddle Hsu654a6f92018-07-13 22:59:36 +0800292 display.getRealSize(mMaxVisibleSize);
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700293
294 mDragEnded = false;
Yongjin Kwon9c5f0aa2019-11-06 17:36:24 +0900295
296 try {
297 mClientCallback = win.mClient.asBinder();
298 mClientCallback.linkToDeath(this, 0 /* flags */);
299 } catch (RemoteException e) {
300 // The caller has died, so clean up TaskPositioningController.
301 mService.mTaskPositioningController.finishTaskPositioning();
302 return;
303 }
304 mWindow = win;
305 mTask = win.getTask();
Chong Zhang8e89b312015-09-09 15:09:30 -0700306 }
307
308 void unregister() {
309 if (DEBUG_TASK_POSITIONING) {
310 Slog.d(TAG, "Unregistering task positioner");
311 }
312
313 if (mClientChannel == null) {
314 Slog.e(TAG, "Task positioner not registered");
315 return;
316 }
317
318 mService.mInputManager.unregisterInputChannel(mServerChannel);
319
320 mInputEventReceiver.dispose();
321 mInputEventReceiver = null;
322 mClientChannel.dispose();
323 mServerChannel.dispose();
324 mClientChannel = null;
325 mServerChannel = null;
326
327 mDragWindowHandle = null;
328 mDragApplicationHandle = null;
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700329 mDragEnded = true;
Wale Ogunwale228d4042015-09-13 10:17:34 -0700330
Garfield Tan07544cd2018-09-12 16:16:54 -0700331 // Notify InputMonitor to remove mDragWindowHandle.
332 mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
333
Chong Zhang8e89b312015-09-09 15:09:30 -0700334 // Resume rotations after a drag.
Adrian Roosb125e0b2019-10-02 14:55:14 +0200335 ProtoLog.d(WM_DEBUG_ORIENTATION, "Resuming rotation after re-position");
Riddle Hsuccf09402019-08-13 00:33:06 +0800336 mDisplayContent.getDisplayRotation().resume();
Riddle Hsu654a6f92018-07-13 22:59:36 +0800337 mDisplayContent = null;
Yongjin Kwon9c5f0aa2019-11-06 17:36:24 +0900338 if (mClientCallback != null) {
339 mClientCallback.unlinkToDeath(this, 0 /* flags */);
340 }
341 mWindow = null;
Chong Zhang8e89b312015-09-09 15:09:30 -0700342 }
343
Yongjin Kwon9c5f0aa2019-11-06 17:36:24 +0900344 void startDrag(boolean resize, boolean preserveOrientation, float startX,
345 float startY) {
Wale Ogunwale228d4042015-09-13 10:17:34 -0700346 if (DEBUG_TASK_POSITIONING) {
Yongjin Kwon9c5f0aa2019-11-06 17:36:24 +0900347 Slog.d(TAG, "startDrag: win=" + mWindow + ", resize=" + resize
skuhne@google.com322347b2016-12-02 12:54:03 -0800348 + ", preserveOrientation=" + preserveOrientation + ", {" + startX + ", "
349 + startY + "}");
Chong Zhang8e89b312015-09-09 15:09:30 -0700350 }
Evan Rosky0d654cb2019-02-26 10:59:10 -0800351 // Use the bounds of the task which accounts for
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700352 // multiple app windows. Don't use any bounds from win itself as it
353 // may not be the same size as the task.
Evan Rosky0d654cb2019-02-26 10:59:10 -0800354 mTask.getBounds(mTmpRect);
skuhne@google.com322347b2016-12-02 12:54:03 -0800355 startDrag(resize, preserveOrientation, startX, startY, mTmpRect);
356 }
357
Daichi Hirono43094a12018-05-31 12:32:23 +0900358 protected void startDrag(boolean resize, boolean preserveOrientation,
skuhne@google.com322347b2016-12-02 12:54:03 -0800359 float startX, float startY, Rect startBounds) {
360 mCtrlType = CTRL_NONE;
361 mStartDragX = startX;
362 mStartDragY = startY;
363 mPreserveOrientation = preserveOrientation;
Chong Zhangd8ceb852015-11-11 14:53:41 -0800364
Chong Zhang8e89b312015-09-09 15:09:30 -0700365 if (resize) {
skuhne@google.com322347b2016-12-02 12:54:03 -0800366 if (startX < startBounds.left) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700367 mCtrlType |= CTRL_LEFT;
368 }
skuhne@google.com322347b2016-12-02 12:54:03 -0800369 if (startX > startBounds.right) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700370 mCtrlType |= CTRL_RIGHT;
371 }
skuhne@google.com322347b2016-12-02 12:54:03 -0800372 if (startY < startBounds.top) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700373 mCtrlType |= CTRL_TOP;
374 }
skuhne@google.com322347b2016-12-02 12:54:03 -0800375 if (startY > startBounds.bottom) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700376 mCtrlType |= CTRL_BOTTOM;
377 }
skuhne@google.com322347b2016-12-02 12:54:03 -0800378 mResizing = mCtrlType != CTRL_NONE;
Chong Zhang8e89b312015-09-09 15:09:30 -0700379 }
380
skuhne@google.com322347b2016-12-02 12:54:03 -0800381 // In case of !isDockedInEffect we are using the union of all task bounds. These might be
382 // made up out of multiple windows which are only partially overlapping. When that happens,
383 // the orientation from the window of interest to the entire stack might diverge. However
384 // for now we treat them as the same.
385 mStartOrientationWasLandscape = startBounds.width() >= startBounds.height();
386 mWindowOriginalBounds.set(startBounds);
Vladislav Kaznacheev824bc5d2016-04-22 17:48:35 -0700387
Tomasz Mikolajewski79e8d172017-11-21 11:21:42 +0900388 // Notify the app that resizing has started, even though we haven't received any new
389 // bounds yet. This will guarantee that the app starts the backdrop renderer before
390 // configuration changes which could cause an activity restart.
391 if (mResizing) {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700392 synchronized (mService.mGlobalLock) {
Tomasz Mikolajewski79e8d172017-11-21 11:21:42 +0900393 notifyMoveLocked(startX, startY);
394 }
395
396 // Perform the resize on the WMS handler thread when we don't have the WMS lock held
397 // to ensure that we don't deadlock WMS and AMS. Note that WindowPositionerEventReceiver
398 // callbacks are delivered on the same handler so this initial resize is always
399 // guaranteed to happen before subsequent drag resizes.
400 mService.mH.post(() -> {
401 try {
Daichi Hirono67f2f4b2018-05-25 16:07:30 +0900402 mActivityManager.resizeTask(
Tomasz Mikolajewski79e8d172017-11-21 11:21:42 +0900403 mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
404 } catch (RemoteException e) {
405 }
406 });
407 }
408
Vladislav Kaznacheev824bc5d2016-04-22 17:48:35 -0700409 // Make sure we always have valid drag bounds even if the drag ends before any move events
410 // have been handled.
skuhne@google.com322347b2016-12-02 12:54:03 -0800411 mWindowDragBounds.set(startBounds);
Chong Zhang3005e752015-09-18 18:46:28 -0700412 }
413
414 private void endDragLocked() {
415 mResizing = false;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +0100416 mTask.setDragResizing(false, DRAG_RESIZE_MODE_FREEFORM);
Chong Zhang8e89b312015-09-09 15:09:30 -0700417 }
418
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700419 /** Returns true if the move operation should be ended. */
420 private boolean notifyMoveLocked(float x, float y) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700421 if (DEBUG_TASK_POSITIONING) {
Chong Zhangb15758a2015-11-17 12:12:03 -0800422 Slog.d(TAG, "notifyMoveLocked: {" + x + "," + y + "}");
Chong Zhang8e89b312015-09-09 15:09:30 -0700423 }
424
425 if (mCtrlType != CTRL_NONE) {
skuhne@google.com322347b2016-12-02 12:54:03 -0800426 resizeDrag(x, y);
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +0100427 mTask.setDragResizing(true, DRAG_RESIZE_MODE_FREEFORM);
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700428 return false;
Chong Zhang8e89b312015-09-09 15:09:30 -0700429 }
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700430
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700431 // This is a moving or scrolling operation.
Wale Ogunwale0b3d2922019-12-30 08:55:07 -0800432 mTask.getStack().getDimBounds(mTmpRect);
GyeHun Jeon84b30d22019-04-24 14:20:15 -0700433 // If a target window is covered by system bar, there is no way to move it again by touch.
434 // So we exclude them from stack bounds. and then it will be shown inside stable area.
435 Rect stableBounds = new Rect();
436 mDisplayContent.getStableRect(stableBounds);
437 mTmpRect.intersect(stableBounds);
Chong Zhangb15758a2015-11-17 12:12:03 -0800438
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700439 int nX = (int) x;
440 int nY = (int) y;
Chong Zhangb15758a2015-11-17 12:12:03 -0800441 if (!mTmpRect.contains(nX, nY)) {
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700442 // For a moving operation we allow the pointer to go out of the stack bounds, but
443 // use the clamped pointer position for the drag bounds computation.
444 nX = Math.min(Math.max(nX, mTmpRect.left), mTmpRect.right);
445 nY = Math.min(Math.max(nY, mTmpRect.top), mTmpRect.bottom);
Chong Zhangb15758a2015-11-17 12:12:03 -0800446 }
447
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700448 updateWindowDragBounds(nX, nY, mTmpRect);
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700449 return false;
Chong Zhangb15758a2015-11-17 12:12:03 -0800450 }
451
skuhne@google.com322347b2016-12-02 12:54:03 -0800452 /**
453 * The user is drag - resizing the window.
454 *
455 * @param x The x coordinate of the current drag coordinate.
456 * @param y the y coordinate of the current drag coordinate.
457 */
458 @VisibleForTesting
459 void resizeDrag(float x, float y) {
Ben Lin2e306af2020-02-03 14:23:57 -0800460 updateDraggedBounds(TaskResizingAlgorithm.resizeDrag(x, y, mStartDragX, mStartDragY,
461 mWindowOriginalBounds, mCtrlType, mMinVisibleWidth, mMinVisibleHeight,
462 mMaxVisibleSize, mPreserveOrientation, mStartOrientationWasLandscape));
skuhne@google.com322347b2016-12-02 12:54:03 -0800463 }
464
Ben Lin2e306af2020-02-03 14:23:57 -0800465 private void updateDraggedBounds(Rect newBounds) {
466 mWindowDragBounds.set(newBounds);
skuhne@google.com322347b2016-12-02 12:54:03 -0800467
468 checkBoundsForOrientationViolations(mWindowDragBounds);
469 }
470
471 /**
472 * Validate bounds against orientation violations (if DEBUG_ORIENTATION_VIOLATIONS is set).
473 *
474 * @param bounds The bounds to be checked.
475 */
476 private void checkBoundsForOrientationViolations(Rect bounds) {
477 // When using debug check that we are not violating the given constraints.
478 if (DEBUG_ORIENTATION_VIOLATIONS) {
479 if (mStartOrientationWasLandscape != (bounds.width() >= bounds.height())) {
480 Slog.e(TAG, "Orientation violation detected! should be "
481 + (mStartOrientationWasLandscape ? "landscape" : "portrait")
482 + " but is the other");
483 } else {
484 Slog.v(TAG, "new bounds size: " + bounds.width() + " x " + bounds.height());
485 }
486 if (mMinVisibleWidth > bounds.width() || mMinVisibleHeight > bounds.height()) {
487 Slog.v(TAG, "Minimum requirement violated: Width(min, is)=(" + mMinVisibleWidth
488 + ", " + bounds.width() + ") Height(min,is)=("
489 + mMinVisibleHeight + ", " + bounds.height() + ")");
490 }
491 if (mMaxVisibleSize.x < bounds.width() || mMaxVisibleSize.y < bounds.height()) {
492 Slog.v(TAG, "Maximum requirement violated: Width(min, is)=(" + mMaxVisibleSize.x
493 + ", " + bounds.width() + ") Height(min,is)=("
494 + mMaxVisibleSize.y + ", " + bounds.height() + ")");
495 }
496 }
497 }
498
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700499 private void updateWindowDragBounds(int x, int y, Rect stackBounds) {
500 final int offsetX = Math.round(x - mStartDragX);
501 final int offsetY = Math.round(y - mStartDragY);
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700502 mWindowDragBounds.set(mWindowOriginalBounds);
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700503 // Horizontally, at least mMinVisibleWidth pixels of the window should remain visible.
504 final int maxLeft = stackBounds.right - mMinVisibleWidth;
505 final int minLeft = stackBounds.left + mMinVisibleWidth - mWindowOriginalBounds.width();
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700506
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700507 // Vertically, the top mMinVisibleHeight of the window should remain visible.
508 // (This assumes that the window caption bar is at the top of the window).
509 final int minTop = stackBounds.top;
510 final int maxTop = stackBounds.bottom - mMinVisibleHeight;
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700511
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700512 mWindowDragBounds.offsetTo(
513 Math.min(Math.max(mWindowOriginalBounds.left + offsetX, minLeft), maxLeft),
514 Math.min(Math.max(mWindowOriginalBounds.top + offsetY, minTop), maxTop));
515
Chong Zhangb15758a2015-11-17 12:12:03 -0800516 if (DEBUG_TASK_POSITIONING) Slog.d(TAG,
517 "updateWindowDragBounds: " + mWindowDragBounds);
Chong Zhang8e89b312015-09-09 15:09:30 -0700518 }
519
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700520 public String toShortString() {
521 return TAG;
522 }
Garfield Tan6caf1d8c2018-01-18 12:37:50 -0800523
524 static void setFactory(Factory factory) {
525 sFactory = factory;
526 }
527
528 static TaskPositioner create(WindowManagerService service) {
529 if (sFactory == null) {
530 sFactory = new Factory() {};
531 }
532
533 return sFactory.create(service);
534 }
535
yj81.kwon79c97672019-04-16 19:44:48 -0700536 @Override
537 public void binderDied() {
538 mService.mTaskPositioningController.finishTaskPositioning();
539 }
540
Garfield Tan6caf1d8c2018-01-18 12:37:50 -0800541 interface Factory {
542 default TaskPositioner create(WindowManagerService service) {
543 return new TaskPositioner(service);
544 }
545 }
Wale Ogunwale228d4042015-09-13 10:17:34 -0700546}