Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.server.wm; |
| 18 | |
| 19 | import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; |
| 20 | import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; |
| 21 | |
| 22 | import android.annotation.Nullable; |
Wale Ogunwale | 04d9cb5 | 2018-04-30 13:55:07 -0700 | [diff] [blame] | 23 | import android.app.IActivityTaskManager; |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 24 | import android.graphics.Point; |
| 25 | import android.graphics.Rect; |
Daichi Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 26 | import android.os.Handler; |
chaviw | b5e316c | 2018-12-26 15:39:15 -0800 | [diff] [blame] | 27 | import android.os.IBinder; |
Daichi Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 28 | import android.os.Looper; |
Garfield Tan | 07544cd | 2018-09-12 16:16:54 -0700 | [diff] [blame] | 29 | import android.os.RemoteException; |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 30 | import android.util.Slog; |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 31 | import android.view.Display; |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 32 | import android.view.IWindow; |
Garfield Tan | d427c62 | 2018-11-30 13:00:04 -0800 | [diff] [blame] | 33 | import android.view.InputWindowHandle; |
| 34 | import android.view.SurfaceControl; |
Garfield Tan | 07544cd | 2018-09-12 16:16:54 -0700 | [diff] [blame] | 35 | |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 36 | import com.android.internal.annotations.GuardedBy; |
| 37 | import com.android.server.input.InputManagerService; |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 38 | |
| 39 | /** |
| 40 | * Controller for task positioning by drag. |
| 41 | */ |
| 42 | class TaskPositioningController { |
| 43 | private final WindowManagerService mService; |
| 44 | private final InputManagerService mInputManager; |
Wale Ogunwale | 04d9cb5 | 2018-04-30 13:55:07 -0700 | [diff] [blame] | 45 | private final IActivityTaskManager mActivityManager; |
Daichi Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 46 | private final Handler mHandler; |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 47 | private SurfaceControl mInputSurface; |
| 48 | private DisplayContent mPositioningDisplay; |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 49 | |
| 50 | @GuardedBy("WindowManagerSerivce.mWindowMap") |
| 51 | private @Nullable TaskPositioner mTaskPositioner; |
| 52 | |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 53 | private final Rect mTmpClipRect = new Rect(); |
chaviw | b5e316c | 2018-12-26 15:39:15 -0800 | [diff] [blame] | 54 | private IBinder mTransferTouchFromToken; |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 55 | |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 56 | 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 Hung | 95b38a9 | 2018-07-20 18:56:12 +0800 | [diff] [blame] | 65 | IActivityTaskManager activityManager, Looper looper) { |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 66 | mService = service; |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 67 | mInputManager = inputManager; |
| 68 | mActivityManager = activityManager; |
Daichi Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 69 | mHandler = new Handler(looper); |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 70 | } |
| 71 | |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 72 | 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 Weingarten | 6ef9cc6 | 2019-02-07 16:28:45 +0000 | [diff] [blame] | 86 | .setContainerLayer() |
Vishnu Nair | e86bd98 | 2018-11-28 13:23:17 -0800 | [diff] [blame] | 87 | .setName("Drag and Drop Input Consumer").build(); |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 88 | } |
| 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); |
chaviw | b5e316c | 2018-12-26 15:39:15 -0800 | [diff] [blame] | 107 | t.transferTouchFocus(mTransferTouchFromToken, h.token); |
| 108 | mTransferTouchFromToken = null; |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 109 | } |
| 110 | |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 111 | boolean startMovingTask(IWindow window, float startX, float startY) { |
| 112 | WindowState win = null; |
Wale Ogunwale | db485de | 2018-10-29 09:47:07 -0700 | [diff] [blame] | 113 | synchronized (mService.mGlobalLock) { |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 114 | 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 Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 129 | mHandler.post(() -> { |
| 130 | int taskId = -1; |
Wale Ogunwale | db485de | 2018-10-29 09:47:07 -0700 | [diff] [blame] | 131 | synchronized (mService.mGlobalLock) { |
Daichi Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 132 | 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 Tan | 4f71c5a | 2018-10-10 10:12:02 -0700 | [diff] [blame] | 140 | taskId = displayContent.taskForTapOutside(x, y); |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 141 | } |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 142 | } |
Daichi Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 143 | if (taskId >= 0) { |
| 144 | try { |
| 145 | mActivityManager.setFocusedTask(taskId); |
| 146 | } catch (RemoteException e) { |
| 147 | } |
| 148 | } |
| 149 | }); |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 150 | } |
| 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 Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 174 | mPositioningDisplay = displayContent; |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 175 | |
Garfield Tan | 6caf1d8c | 2018-01-18 12:37:50 -0800 | [diff] [blame] | 176 | mTaskPositioner = TaskPositioner.create(mService); |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 177 | |
| 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 Huang | 1e5b10a | 2018-07-30 20:19:51 +0800 | [diff] [blame] | 183 | if (displayContent.mCurrentFocus != null && displayContent.mCurrentFocus != win |
| 184 | && displayContent.mCurrentFocus.mAppToken == win.mAppToken) { |
| 185 | transferFocusFromWin = displayContent.mCurrentFocus; |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 186 | } |
chaviw | b5e316c | 2018-12-26 15:39:15 -0800 | [diff] [blame] | 187 | mTransferTouchFromToken = transferFocusFromWin.mInputChannel.getToken(); |
| 188 | mTaskPositioner.register(displayContent); |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 189 | |
| 190 | mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY); |
| 191 | return true; |
| 192 | } |
| 193 | |
Daichi Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 194 | void finishTaskPositioning() { |
| 195 | mHandler.post(() -> { |
| 196 | if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning"); |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 197 | |
Wale Ogunwale | db485de | 2018-10-29 09:47:07 -0700 | [diff] [blame] | 198 | synchronized (mService.mGlobalLock) { |
Garfield Tan | d427c62 | 2018-11-30 13:00:04 -0800 | [diff] [blame] | 199 | cleanUpTaskPositioner(); |
Robert Carr | e92c80c | 2018-08-14 15:38:44 -0700 | [diff] [blame] | 200 | mPositioningDisplay = null; |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 201 | } |
Daichi Hirono | ce2f97a | 2017-11-30 16:44:15 +0900 | [diff] [blame] | 202 | }); |
Daichi Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 203 | } |
Garfield Tan | d427c62 | 2018-11-30 13:00:04 -0800 | [diff] [blame] | 204 | |
| 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 Hirono | 34fb731 | 2017-12-04 10:00:24 +0900 | [diff] [blame] | 216 | } |