blob: 5c321a189c223cfb01673c17fff2f5375413202a [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 Ogunwale59a73ca2015-09-14 12:54:50 -070019import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
20import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
Chong Zhang87b21722015-09-21 15:39:51 -070021import static android.app.ActivityManager.RESIZE_MODE_USER;
Chong Zhang6de2ae82015-09-30 18:25:21 -070022import static android.app.ActivityManager.RESIZE_MODE_USER_FORCED;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080023import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
Wale Ogunwale228d4042015-09-13 10:17:34 -070024import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
Wale Ogunwalecad05a02015-09-25 10:41:44 -070025import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080026import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
28import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
29import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
30import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -070031import static com.android.server.wm.WindowManagerService.dipToPixel;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +010032import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
Wale Ogunwale231b06e2015-09-16 12:03:09 -070033import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
34import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
Chong Zhang8e89b312015-09-09 15:09:30 -070035
36import android.annotation.IntDef;
37import android.graphics.Point;
38import android.graphics.Rect;
39import android.os.Looper;
40import android.os.Process;
41import android.os.RemoteException;
Wale Ogunwalecad05a02015-09-25 10:41:44 -070042import android.os.Trace;
Chong Zhang8e89b312015-09-09 15:09:30 -070043import android.util.DisplayMetrics;
44import android.util.Slog;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080045import android.view.BatchedInputEventReceiver;
Wale Ogunwale4f52bc62015-09-24 13:47:31 -070046import android.view.Choreographer;
Chong Zhang8e89b312015-09-09 15:09:30 -070047import android.view.Display;
Wale Ogunwale228d4042015-09-13 10:17:34 -070048import android.view.DisplayInfo;
Chong Zhang8e89b312015-09-09 15:09:30 -070049import android.view.InputChannel;
50import android.view.InputDevice;
51import android.view.InputEvent;
Chong Zhang8e89b312015-09-09 15:09:30 -070052import android.view.MotionEvent;
Wale Ogunwale228d4042015-09-13 10:17:34 -070053import android.view.SurfaceControl;
Chong Zhang8e89b312015-09-09 15:09:30 -070054import android.view.WindowManager;
55
Wale Ogunwale228d4042015-09-13 10:17:34 -070056import com.android.server.input.InputApplicationHandle;
57import com.android.server.input.InputWindowHandle;
58import com.android.server.wm.WindowManagerService.H;
59
60import java.lang.annotation.Retention;
61import java.lang.annotation.RetentionPolicy;
62
63class TaskPositioner implements DimLayer.DimLayerUser {
Jorim Jaggibc5425c2016-03-01 13:51:16 +010064 private static final String TAG_LOCAL = "TaskPositioner";
65 private static final String TAG = TAG_WITH_CLASS_NAME ? TAG_LOCAL : TAG_WM;
Chong Zhang8e89b312015-09-09 15:09:30 -070066
Wale Ogunwale228d4042015-09-13 10:17:34 -070067 // The margin the pointer position has to be within the side of the screen to be
68 // considered at the side of the screen.
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -070069 static final int SIDE_MARGIN_DIP = 100;
Wale Ogunwale228d4042015-09-13 10:17:34 -070070
Chong Zhang8e89b312015-09-09 15:09:30 -070071 @IntDef(flag = true,
72 value = {
73 CTRL_NONE,
74 CTRL_LEFT,
75 CTRL_RIGHT,
76 CTRL_TOP,
77 CTRL_BOTTOM
78 })
79 @Retention(RetentionPolicy.SOURCE)
80 @interface CtrlType {}
81
82 private static final int CTRL_NONE = 0x0;
83 private static final int CTRL_LEFT = 0x1;
84 private static final int CTRL_RIGHT = 0x2;
85 private static final int CTRL_TOP = 0x4;
86 private static final int CTRL_BOTTOM = 0x8;
87
Filip Gruszczynski64b6b442016-01-18 13:20:58 -080088 public static final float RESIZING_HINT_ALPHA = 0.5f;
89
90 public static final int RESIZING_HINT_DURATION_MS = 0;
91
Chong Zhang8e89b312015-09-09 15:09:30 -070092 private final WindowManagerService mService;
93 private WindowPositionerEventReceiver mInputEventReceiver;
94 private Display mDisplay;
95 private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
Wale Ogunwale228d4042015-09-13 10:17:34 -070096 private DimLayer mDimLayer;
97 @CtrlType
98 private int mCurrentDimSide;
99 private Rect mTmpRect = new Rect();
100 private int mSideMargin;
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700101 private int mMinVisibleWidth;
102 private int mMinVisibleHeight;
Chong Zhang8e89b312015-09-09 15:09:30 -0700103
Chong Zhang3005e752015-09-18 18:46:28 -0700104 private Task mTask;
Chong Zhang09b21ef2015-09-14 10:20:21 -0700105 private boolean mResizing;
Chong Zhang8e89b312015-09-09 15:09:30 -0700106 private final Rect mWindowOriginalBounds = new Rect();
107 private final Rect mWindowDragBounds = new Rect();
108 private float mStartDragX;
109 private float mStartDragY;
110 @CtrlType
111 private int mCtrlType = CTRL_NONE;
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700112 private boolean mDragEnded = false;
Chong Zhang8e89b312015-09-09 15:09:30 -0700113
114 InputChannel mServerChannel;
115 InputChannel mClientChannel;
116 InputApplicationHandle mDragApplicationHandle;
117 InputWindowHandle mDragWindowHandle;
118
Wale Ogunwale4f52bc62015-09-24 13:47:31 -0700119 private final class WindowPositionerEventReceiver extends BatchedInputEventReceiver {
120 public WindowPositionerEventReceiver(
121 InputChannel inputChannel, Looper looper, Choreographer choreographer) {
122 super(inputChannel, looper, choreographer);
Chong Zhang8e89b312015-09-09 15:09:30 -0700123 }
124
125 @Override
126 public void onInputEvent(InputEvent event) {
127 if (!(event instanceof MotionEvent)
128 || (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
129 return;
130 }
131 final MotionEvent motionEvent = (MotionEvent) event;
132 boolean handled = false;
133
134 try {
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700135 if (mDragEnded) {
136 // The drag has ended but the clean-up message has not been processed by
137 // window manager. Drop events that occur after this until window manager
138 // has a chance to clean-up the input handle.
139 handled = true;
140 return;
141 }
142
Chong Zhang8e89b312015-09-09 15:09:30 -0700143 final float newX = motionEvent.getRawX();
144 final float newY = motionEvent.getRawY();
145
146 switch (motionEvent.getAction()) {
147 case MotionEvent.ACTION_DOWN: {
148 if (DEBUG_TASK_POSITIONING) {
149 Slog.w(TAG, "ACTION_DOWN @ {" + newX + ", " + newY + "}");
150 }
151 } break;
152
153 case MotionEvent.ACTION_MOVE: {
154 if (DEBUG_TASK_POSITIONING){
155 Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}");
156 }
157 synchronized (mService.mWindowMap) {
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700158 mDragEnded = notifyMoveLocked(newX, newY);
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800159 mTask.getDimBounds(mTmpRect);
Chong Zhang8e89b312015-09-09 15:09:30 -0700160 }
Wale Ogunwale04ad7b12015-10-02 12:43:27 -0700161 if (!mTmpRect.equals(mWindowDragBounds)) {
162 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
163 "wm.TaskPositioner.resizeTask");
164 try {
165 mService.mActivityManager.resizeTask(
166 mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
167 } catch (RemoteException e) {
168 }
169 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
170 }
Chong Zhang8e89b312015-09-09 15:09:30 -0700171 } break;
172
173 case MotionEvent.ACTION_UP: {
174 if (DEBUG_TASK_POSITIONING) {
175 Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}");
176 }
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700177 mDragEnded = true;
Chong Zhang8e89b312015-09-09 15:09:30 -0700178 } break;
179
180 case MotionEvent.ACTION_CANCEL: {
181 if (DEBUG_TASK_POSITIONING) {
182 Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}");
183 }
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700184 mDragEnded = true;
Chong Zhang8e89b312015-09-09 15:09:30 -0700185 } break;
186 }
187
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700188 if (mDragEnded) {
Wale Ogunwale04ad7b12015-10-02 12:43:27 -0700189 final boolean wasResizing = mResizing;
Chong Zhang3005e752015-09-18 18:46:28 -0700190 synchronized (mService.mWindowMap) {
191 endDragLocked();
Vladislav Kaznacheev824bc5d2016-04-22 17:48:35 -0700192 mTask.getDimBounds(mTmpRect);
Chong Zhang3005e752015-09-18 18:46:28 -0700193 }
Chong Zhang09b21ef2015-09-14 10:20:21 -0700194 try {
Vladislav Kaznacheev824bc5d2016-04-22 17:48:35 -0700195 if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
Chong Zhang3005e752015-09-18 18:46:28 -0700196 // We were using fullscreen surface during resizing. Request
197 // resizeTask() one last time to restore surface to window size.
198 mService.mActivityManager.resizeTask(
Chong Zhang6de2ae82015-09-30 18:25:21 -0700199 mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
Chong Zhang3005e752015-09-18 18:46:28 -0700200 }
201
202 if (mCurrentDimSide != CTRL_NONE) {
203 final int createMode = mCurrentDimSide == CTRL_LEFT
204 ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
205 : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
206 mService.mActivityManager.moveTaskToDockedStack(
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800207 mTask.mTaskId, createMode, true /*toTop*/, true /* animate */,
Wale Ogunwalea4d92a02016-05-01 16:02:16 -0700208 null /* initialBounds */, false /* moveHomeStackFront */);
Chong Zhang3005e752015-09-18 18:46:28 -0700209 }
Chong Zhang09b21ef2015-09-14 10:20:21 -0700210 } catch(RemoteException e) {}
Chong Zhang3005e752015-09-18 18:46:28 -0700211
Chong Zhang8e89b312015-09-09 15:09:30 -0700212 // Post back to WM to handle clean-ups. We still need the input
213 // event handler for the last finishInputEvent()!
214 mService.mH.sendEmptyMessage(H.FINISH_TASK_POSITIONING);
215 }
216 handled = true;
217 } catch (Exception e) {
218 Slog.e(TAG, "Exception caught by drag handleMotion", e);
219 } finally {
220 finishInputEvent(event, handled);
221 }
222 }
223 }
224
225 TaskPositioner(WindowManagerService service) {
226 mService = service;
227 }
228
229 /**
230 * @param display The Display that the window being dragged is on.
231 */
232 void register(Display display) {
233 if (DEBUG_TASK_POSITIONING) {
234 Slog.d(TAG, "Registering task positioner");
235 }
236
237 if (mClientChannel != null) {
238 Slog.e(TAG, "Task positioner already registered");
239 return;
240 }
241
242 mDisplay = display;
243 mDisplay.getMetrics(mDisplayMetrics);
244 final InputChannel[] channels = InputChannel.openInputChannelPair(TAG);
245 mServerChannel = channels[0];
246 mClientChannel = channels[1];
247 mService.mInputManager.registerInputChannel(mServerChannel, null);
248
Wale Ogunwale4f52bc62015-09-24 13:47:31 -0700249 mInputEventReceiver = new WindowPositionerEventReceiver(
250 mClientChannel, mService.mH.getLooper(), mService.mChoreographer);
Chong Zhang8e89b312015-09-09 15:09:30 -0700251
252 mDragApplicationHandle = new InputApplicationHandle(null);
253 mDragApplicationHandle.name = TAG;
254 mDragApplicationHandle.dispatchingTimeoutNanos =
255 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
256
257 mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
258 mDisplay.getDisplayId());
259 mDragWindowHandle.name = TAG;
260 mDragWindowHandle.inputChannel = mServerChannel;
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -0700261 mDragWindowHandle.layer = mService.getDragLayerLocked();
Chong Zhang8e89b312015-09-09 15:09:30 -0700262 mDragWindowHandle.layoutParamsFlags = 0;
263 mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
264 mDragWindowHandle.dispatchingTimeoutNanos =
265 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
266 mDragWindowHandle.visible = true;
267 mDragWindowHandle.canReceiveKeys = false;
268 mDragWindowHandle.hasFocus = true;
269 mDragWindowHandle.hasWallpaper = false;
270 mDragWindowHandle.paused = false;
271 mDragWindowHandle.ownerPid = Process.myPid();
272 mDragWindowHandle.ownerUid = Process.myUid();
273 mDragWindowHandle.inputFeatures = 0;
274 mDragWindowHandle.scaleFactor = 1.0f;
275
276 // The drag window cannot receive new touches.
277 mDragWindowHandle.touchableRegion.setEmpty();
278
279 // The drag window covers the entire display
280 mDragWindowHandle.frameLeft = 0;
281 mDragWindowHandle.frameTop = 0;
282 final Point p = new Point();
283 mDisplay.getRealSize(p);
284 mDragWindowHandle.frameRight = p.x;
285 mDragWindowHandle.frameBottom = p.y;
286
287 // Pause rotations before a drag.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800288 if (DEBUG_ORIENTATION) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700289 Slog.d(TAG, "Pausing rotation during re-position");
290 }
291 mService.pauseRotationLocked();
Wale Ogunwale228d4042015-09-13 10:17:34 -0700292
Jorim Jaggibc5425c2016-03-01 13:51:16 +0100293 mDimLayer = new DimLayer(mService, this, mDisplay.getDisplayId(), TAG_LOCAL);
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -0700294 mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
295 mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
296 mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700297
298 mDragEnded = false;
Chong Zhang8e89b312015-09-09 15:09:30 -0700299 }
300
301 void unregister() {
302 if (DEBUG_TASK_POSITIONING) {
303 Slog.d(TAG, "Unregistering task positioner");
304 }
305
306 if (mClientChannel == null) {
307 Slog.e(TAG, "Task positioner not registered");
308 return;
309 }
310
311 mService.mInputManager.unregisterInputChannel(mServerChannel);
312
313 mInputEventReceiver.dispose();
314 mInputEventReceiver = null;
315 mClientChannel.dispose();
316 mServerChannel.dispose();
317 mClientChannel = null;
318 mServerChannel = null;
319
320 mDragWindowHandle = null;
321 mDragApplicationHandle = null;
322 mDisplay = null;
323
Wale Ogunwale228d4042015-09-13 10:17:34 -0700324 if (mDimLayer != null) {
325 mDimLayer.destroySurface();
326 mDimLayer = null;
327 }
328 mCurrentDimSide = CTRL_NONE;
Wale Ogunwale6a804b82015-09-23 21:04:21 -0700329 mDragEnded = true;
Wale Ogunwale228d4042015-09-13 10:17:34 -0700330
Chong Zhang8e89b312015-09-09 15:09:30 -0700331 // Resume rotations after a drag.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800332 if (DEBUG_ORIENTATION) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700333 Slog.d(TAG, "Resuming rotation after re-position");
334 }
335 mService.resumeRotationLocked();
336 }
337
338 void startDragLocked(WindowState win, boolean resize, float startX, float startY) {
Wale Ogunwale228d4042015-09-13 10:17:34 -0700339 if (DEBUG_TASK_POSITIONING) {
340 Slog.d(TAG, "startDragLocked: win=" + win + ", resize=" + resize
Chong Zhang8e89b312015-09-09 15:09:30 -0700341 + ", {" + startX + ", " + startY + "}");
342 }
343 mCtrlType = CTRL_NONE;
Chong Zhangd8ceb852015-11-11 14:53:41 -0800344 mTask = win.getTask();
345 mStartDragX = startX;
346 mStartDragY = startY;
347
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700348 // Use the dim bounds, not the original task bounds. The cursor
349 // movement should be calculated relative to the visible bounds.
350 // Also, use the dim bounds of the task which accounts for
351 // multiple app windows. Don't use any bounds from win itself as it
352 // may not be the same size as the task.
353 mTask.getDimBounds(mTmpRect);
Chong Zhangd8ceb852015-11-11 14:53:41 -0800354
Chong Zhang8e89b312015-09-09 15:09:30 -0700355 if (resize) {
Chong Zhangd8ceb852015-11-11 14:53:41 -0800356 if (startX < mTmpRect.left) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700357 mCtrlType |= CTRL_LEFT;
358 }
Chong Zhangd8ceb852015-11-11 14:53:41 -0800359 if (startX > mTmpRect.right) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700360 mCtrlType |= CTRL_RIGHT;
361 }
Chong Zhangd8ceb852015-11-11 14:53:41 -0800362 if (startY < mTmpRect.top) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700363 mCtrlType |= CTRL_TOP;
364 }
Chong Zhangd8ceb852015-11-11 14:53:41 -0800365 if (startY > mTmpRect.bottom) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700366 mCtrlType |= CTRL_BOTTOM;
367 }
Chong Zhang09b21ef2015-09-14 10:20:21 -0700368 mResizing = true;
Chong Zhang8e89b312015-09-09 15:09:30 -0700369 }
370
Chong Zhangd8ceb852015-11-11 14:53:41 -0800371 mWindowOriginalBounds.set(mTmpRect);
Vladislav Kaznacheev824bc5d2016-04-22 17:48:35 -0700372
373 // Make sure we always have valid drag bounds even if the drag ends before any move events
374 // have been handled.
375 mWindowDragBounds.set(mTmpRect);
Chong Zhang3005e752015-09-18 18:46:28 -0700376 }
377
378 private void endDragLocked() {
379 mResizing = false;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +0100380 mTask.setDragResizing(false, DRAG_RESIZE_MODE_FREEFORM);
Chong Zhang8e89b312015-09-09 15:09:30 -0700381 }
382
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700383 /** Returns true if the move operation should be ended. */
384 private boolean notifyMoveLocked(float x, float y) {
Chong Zhang8e89b312015-09-09 15:09:30 -0700385 if (DEBUG_TASK_POSITIONING) {
Chong Zhangb15758a2015-11-17 12:12:03 -0800386 Slog.d(TAG, "notifyMoveLocked: {" + x + "," + y + "}");
Chong Zhang8e89b312015-09-09 15:09:30 -0700387 }
388
389 if (mCtrlType != CTRL_NONE) {
390 // This is a resizing operation.
391 final int deltaX = Math.round(x - mStartDragX);
392 final int deltaY = Math.round(y - mStartDragY);
Chong Zhang8e89b312015-09-09 15:09:30 -0700393 int left = mWindowOriginalBounds.left;
394 int top = mWindowOriginalBounds.top;
395 int right = mWindowOriginalBounds.right;
396 int bottom = mWindowOriginalBounds.bottom;
397 if ((mCtrlType & CTRL_LEFT) != 0) {
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700398 left = Math.min(left + deltaX, right - mMinVisibleWidth);
Chong Zhang8e89b312015-09-09 15:09:30 -0700399 }
400 if ((mCtrlType & CTRL_TOP) != 0) {
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700401 top = Math.min(top + deltaY, bottom - mMinVisibleHeight);
Chong Zhang8e89b312015-09-09 15:09:30 -0700402 }
403 if ((mCtrlType & CTRL_RIGHT) != 0) {
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700404 right = Math.max(left + mMinVisibleWidth, right + deltaX);
Chong Zhang8e89b312015-09-09 15:09:30 -0700405 }
406 if ((mCtrlType & CTRL_BOTTOM) != 0) {
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700407 bottom = Math.max(top + mMinVisibleHeight, bottom + deltaY);
Chong Zhang8e89b312015-09-09 15:09:30 -0700408 }
409 mWindowDragBounds.set(left, top, right, bottom);
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +0100410 mTask.setDragResizing(true, DRAG_RESIZE_MODE_FREEFORM);
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700411 return false;
Chong Zhang8e89b312015-09-09 15:09:30 -0700412 }
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700413
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700414 // This is a moving or scrolling operation.
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800415 mTask.mStack.getDimBounds(mTmpRect);
Chong Zhangb15758a2015-11-17 12:12:03 -0800416
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700417 int nX = (int) x;
418 int nY = (int) y;
Chong Zhangb15758a2015-11-17 12:12:03 -0800419 if (!mTmpRect.contains(nX, nY)) {
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700420 // For a moving operation we allow the pointer to go out of the stack bounds, but
421 // use the clamped pointer position for the drag bounds computation.
422 nX = Math.min(Math.max(nX, mTmpRect.left), mTmpRect.right);
423 nY = Math.min(Math.max(nY, mTmpRect.top), mTmpRect.bottom);
Chong Zhangb15758a2015-11-17 12:12:03 -0800424 }
425
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700426 updateWindowDragBounds(nX, nY, mTmpRect);
Chong Zhangb15758a2015-11-17 12:12:03 -0800427 updateDimLayerVisibility(nX);
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700428 return false;
Chong Zhangb15758a2015-11-17 12:12:03 -0800429 }
430
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700431 private void updateWindowDragBounds(int x, int y, Rect stackBounds) {
432 final int offsetX = Math.round(x - mStartDragX);
433 final int offsetY = Math.round(y - mStartDragY);
Wale Ogunwaleb8051b82015-09-17 15:41:52 -0700434 mWindowDragBounds.set(mWindowOriginalBounds);
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700435 // Horizontally, at least mMinVisibleWidth pixels of the window should remain visible.
436 final int maxLeft = stackBounds.right - mMinVisibleWidth;
437 final int minLeft = stackBounds.left + mMinVisibleWidth - mWindowOriginalBounds.width();
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700438
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700439 // Vertically, the top mMinVisibleHeight of the window should remain visible.
440 // (This assumes that the window caption bar is at the top of the window).
441 final int minTop = stackBounds.top;
442 final int maxTop = stackBounds.bottom - mMinVisibleHeight;
Vladislav Kaznacheeva90a3b82016-04-27 14:54:53 -0700443
Chong Zhang2e2c81a2016-07-15 11:28:17 -0700444 mWindowDragBounds.offsetTo(
445 Math.min(Math.max(mWindowOriginalBounds.left + offsetX, minLeft), maxLeft),
446 Math.min(Math.max(mWindowOriginalBounds.top + offsetY, minTop), maxTop));
447
Chong Zhangb15758a2015-11-17 12:12:03 -0800448 if (DEBUG_TASK_POSITIONING) Slog.d(TAG,
449 "updateWindowDragBounds: " + mWindowDragBounds);
Chong Zhang8e89b312015-09-09 15:09:30 -0700450 }
451
Wale Ogunwale228d4042015-09-13 10:17:34 -0700452 private void updateDimLayerVisibility(int x) {
453 @CtrlType
454 int dimSide = getDimSide(x);
455 if (dimSide == mCurrentDimSide) {
456 return;
457 }
458
459 mCurrentDimSide = dimSide;
460
461 if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION updateDimLayerVisibility");
462 SurfaceControl.openTransaction();
463 if (mCurrentDimSide == CTRL_NONE) {
464 mDimLayer.hide();
465 } else {
466 showDimLayer();
467 }
468 SurfaceControl.closeTransaction();
469 }
470
471 /**
472 * Returns the side of the screen the dim layer should be shown.
473 * @param x horizontal coordinate used to determine if the dim layer should be shown
474 * @return Returns {@link #CTRL_LEFT} if the dim layer should be shown on the left half of the
475 * screen, {@link #CTRL_RIGHT} if on the right side, or {@link #CTRL_NONE} if the dim layer
476 * shouldn't be shown.
477 */
478 private int getDimSide(int x) {
Chong Zhang3005e752015-09-18 18:46:28 -0700479 if (mTask.mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID
480 || !mTask.mStack.isFullscreen()
Wale Ogunwale228d4042015-09-13 10:17:34 -0700481 || mService.mCurConfiguration.orientation != ORIENTATION_LANDSCAPE) {
482 return CTRL_NONE;
483 }
484
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800485 mTask.mStack.getDimBounds(mTmpRect);
Wale Ogunwale228d4042015-09-13 10:17:34 -0700486 if (x - mSideMargin <= mTmpRect.left) {
487 return CTRL_LEFT;
488 }
489 if (x + mSideMargin >= mTmpRect.right) {
490 return CTRL_RIGHT;
491 }
492
493 return CTRL_NONE;
494 }
495
496 private void showDimLayer() {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800497 mTask.mStack.getDimBounds(mTmpRect);
Wale Ogunwale228d4042015-09-13 10:17:34 -0700498 if (mCurrentDimSide == CTRL_LEFT) {
499 mTmpRect.right = mTmpRect.centerX();
500 } else if (mCurrentDimSide == CTRL_RIGHT) {
501 mTmpRect.left = mTmpRect.centerX();
502 }
503
504 mDimLayer.setBounds(mTmpRect);
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -0700505 mDimLayer.show(mService.getDragLayerLocked(), RESIZING_HINT_ALPHA,
506 RESIZING_HINT_DURATION_MS);
Wale Ogunwale228d4042015-09-13 10:17:34 -0700507 }
508
509 @Override /** {@link DimLayer.DimLayerUser} */
Wale Ogunwale29bfbb82016-05-12 15:13:52 -0700510 public boolean dimFullscreen() {
511 return isFullscreen();
512 }
513
514 boolean isFullscreen() {
Wale Ogunwale228d4042015-09-13 10:17:34 -0700515 return false;
516 }
517
518 @Override /** {@link DimLayer.DimLayerUser} */
519 public DisplayInfo getDisplayInfo() {
Chong Zhang3005e752015-09-18 18:46:28 -0700520 return mTask.mStack.getDisplayInfo();
Wale Ogunwale228d4042015-09-13 10:17:34 -0700521 }
522
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700523 @Override
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800524 public void getDimBounds(Rect out) {
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700525 // This dim layer user doesn't need this.
526 }
527
528 @Override
529 public String toShortString() {
530 return TAG;
531 }
Wale Ogunwale228d4042015-09-13 10:17:34 -0700532}