• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
23 import android.graphics.Point;
24 import android.graphics.Rect;
25 import android.util.Slog;
26 import android.view.Display;
27 import android.view.IWindow;
28 import android.view.InputWindowHandle;
29 import android.view.SurfaceControl;
30 
31 /**
32  * Controller for task positioning by drag.
33  */
34 class TaskPositioningController {
35     private final WindowManagerService mService;
36     private SurfaceControl mInputSurface;
37     private DisplayContent mPositioningDisplay;
38 
39     private @Nullable TaskPositioner mTaskPositioner;
40 
41     private final Rect mTmpClipRect = new Rect();
42 
isPositioningLocked()43     boolean isPositioningLocked() {
44         return mTaskPositioner != null;
45     }
46 
47     final SurfaceControl.Transaction mTransaction;
48 
getDragWindowHandleLocked()49     InputWindowHandle getDragWindowHandleLocked() {
50         return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
51     }
52 
TaskPositioningController(WindowManagerService service)53     TaskPositioningController(WindowManagerService service) {
54         mService = service;
55         mTransaction = service.mTransactionFactory.get();
56     }
57 
hideInputSurface(int displayId)58     void hideInputSurface(int displayId) {
59         if (mPositioningDisplay != null && mPositioningDisplay.getDisplayId() == displayId
60                 && mInputSurface != null) {
61             mTransaction.hide(mInputSurface);
62             mTransaction.syncInputWindows().apply();
63         }
64     }
65 
showInputSurface(int displayId)66     void showInputSurface(int displayId) {
67         if (mPositioningDisplay == null || mPositioningDisplay.getDisplayId() != displayId) {
68             return;
69         }
70         final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
71         if (mInputSurface == null) {
72             mInputSurface = mService.makeSurfaceBuilder(dc.getSession())
73                     .setContainerLayer()
74                     .setName("Drag and Drop Input Consumer")
75                     .setCallsite("TaskPositioningController.showInputSurface")
76                     .setParent(dc.getOverlayLayer())
77                     .build();
78         }
79 
80         final InputWindowHandle h = getDragWindowHandleLocked();
81         if (h == null) {
82             Slog.w(TAG_WM, "Drag is in progress but there is no "
83                     + "drag window handle.");
84             return;
85         }
86 
87         final Display display = dc.getDisplay();
88         final Point p = new Point();
89         display.getRealSize(p);
90         mTmpClipRect.set(0, 0, p.x, p.y);
91 
92         mTransaction.show(mInputSurface)
93                 .setInputWindowInfo(mInputSurface, h)
94                 .setLayer(mInputSurface, Integer.MAX_VALUE)
95                 .setPosition(mInputSurface, 0, 0)
96                 .setCrop(mInputSurface, mTmpClipRect)
97                 .syncInputWindows()
98                 .apply();
99     }
100 
startMovingTask(IWindow window, float startX, float startY)101     boolean startMovingTask(IWindow window, float startX, float startY) {
102         WindowState win = null;
103         synchronized (mService.mGlobalLock) {
104             win = mService.windowForClientLocked(null, window, false);
105             // win shouldn't be null here, pass it down to startPositioningLocked
106             // to get warning if it's null.
107             if (!startPositioningLocked(
108                     win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
109                 return false;
110             }
111             mService.mAtmService.setFocusedTask(win.getTask().mTaskId);
112         }
113         return true;
114     }
115 
handleTapOutsideTask(DisplayContent displayContent, int x, int y)116     void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
117         mService.mH.post(() -> {
118             synchronized (mService.mGlobalLock) {
119                 final Task task = displayContent.findTaskForResizePoint(x, y);
120                 if (task != null) {
121                     if (!task.isResizeable()) {
122                         // The task is not resizable, so don't do anything when the user drags the
123                         // the resize handles.
124                         return;
125                     }
126                     if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
127                             task.preserveOrientationOnResize(), x, y)) {
128                         return;
129                     }
130                     mService.mAtmService.setFocusedTask(task.mTaskId);
131                 }
132             }
133         });
134     }
135 
startPositioningLocked(WindowState win, boolean resize, boolean preserveOrientation, float startX, float startY)136     private boolean startPositioningLocked(WindowState win, boolean resize,
137             boolean preserveOrientation, float startX, float startY) {
138         if (DEBUG_TASK_POSITIONING)
139             Slog.d(TAG_WM, "startPositioningLocked: "
140                     + "win=" + win + ", resize=" + resize + ", preserveOrientation="
141                     + preserveOrientation + ", {" + startX + ", " + startY + "}");
142 
143         if (win == null || win.mActivityRecord == null) {
144             Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
145             return false;
146         }
147         if (win.mInputChannel == null) {
148             Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
149                     + " probably being removed");
150             return false;
151         }
152 
153         final DisplayContent displayContent = win.getDisplayContent();
154         if (displayContent == null) {
155             Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
156             return false;
157         }
158         mPositioningDisplay = displayContent;
159 
160         mTaskPositioner = TaskPositioner.create(mService);
161         mTaskPositioner.register(displayContent, win);
162 
163         // We need to grab the touch focus so that the touch events during the
164         // resizing/scrolling are not sent to the app. 'win' is the main window
165         // of the app, it may not have focus since there might be other windows
166         // on top (eg. a dialog window).
167         WindowState transferFocusFromWin = win;
168         if (displayContent.mCurrentFocus != null && displayContent.mCurrentFocus != win
169                 && displayContent.mCurrentFocus.mActivityRecord == win.mActivityRecord) {
170             transferFocusFromWin = displayContent.mCurrentFocus;
171         }
172         if (!mService.mInputManager.transferTouchFocus(
173                 transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel,
174                 false /* isDragDrop */)) {
175             Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
176             cleanUpTaskPositioner();
177             return false;
178         }
179 
180         mTaskPositioner.startDrag(resize, preserveOrientation, startX, startY);
181         return true;
182     }
183 
finishTaskPositioning(IWindow window)184     public void finishTaskPositioning(IWindow window) {
185         if (mTaskPositioner != null && mTaskPositioner.mClientCallback == window.asBinder()) {
186             finishTaskPositioning();
187         }
188     }
189 
finishTaskPositioning()190     void finishTaskPositioning() {
191         // TaskPositioner attaches the InputEventReceiver to the animation thread. We need to
192         // dispose the receiver on the same thread to avoid race conditions.
193         mService.mAnimationHandler.post(() -> {
194             if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning");
195 
196             synchronized (mService.mGlobalLock) {
197                 cleanUpTaskPositioner();
198                 mPositioningDisplay = null;
199             }
200         });
201     }
202 
cleanUpTaskPositioner()203     private void cleanUpTaskPositioner() {
204         final TaskPositioner positioner = mTaskPositioner;
205         if (positioner == null) {
206             return;
207         }
208 
209         // We need to assign task positioner to null first to indicate that we're finishing task
210         // positioning.
211         mTaskPositioner = null;
212         positioner.unregister();
213     }
214 }
215