• 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.app.IActivityTaskManager;
24 import android.graphics.Point;
25 import android.graphics.Rect;
26 import android.os.Handler;
27 import android.os.IBinder;
28 import android.os.Looper;
29 import android.os.RemoteException;
30 import android.util.Slog;
31 import android.view.Display;
32 import android.view.IWindow;
33 import android.view.InputWindowHandle;
34 import android.view.SurfaceControl;
35 
36 import com.android.internal.annotations.GuardedBy;
37 import com.android.server.input.InputManagerService;
38 
39 /**
40  * Controller for task positioning by drag.
41  */
42 class TaskPositioningController {
43     private final WindowManagerService mService;
44     private final InputManagerService mInputManager;
45     private final IActivityTaskManager mActivityManager;
46     private final Handler mHandler;
47     private SurfaceControl mInputSurface;
48     private DisplayContent mPositioningDisplay;
49 
50     @GuardedBy("WindowManagerSerivce.mWindowMap")
51     private @Nullable TaskPositioner mTaskPositioner;
52 
53     private final Rect mTmpClipRect = new Rect();
54     private IBinder mTransferTouchFromToken;
55 
isPositioningLocked()56     boolean isPositioningLocked() {
57         return mTaskPositioner != null;
58     }
59 
getDragWindowHandleLocked()60     InputWindowHandle getDragWindowHandleLocked() {
61         return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
62     }
63 
TaskPositioningController(WindowManagerService service, InputManagerService inputManager, IActivityTaskManager activityManager, Looper looper)64     TaskPositioningController(WindowManagerService service, InputManagerService inputManager,
65             IActivityTaskManager activityManager, Looper looper) {
66         mService = service;
67         mInputManager = inputManager;
68         mActivityManager = activityManager;
69         mHandler = new Handler(looper);
70     }
71 
hideInputSurface(SurfaceControl.Transaction t, int displayId)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 
showInputSurface(SurfaceControl.Transaction t, int displayId)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())
86                     .setContainerLayer()
87                     .setName("Drag and Drop Input Consumer").build();
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);
107         t.transferTouchFocus(mTransferTouchFromToken, h.token);
108         mTransferTouchFromToken = null;
109     }
110 
startMovingTask(IWindow window, float startX, float startY)111     boolean startMovingTask(IWindow window, float startX, float startY) {
112         WindowState win = null;
113         synchronized (mService.mGlobalLock) {
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 
handleTapOutsideTask(DisplayContent displayContent, int x, int y)128     void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
129         mHandler.post(() -> {
130             synchronized (mService.mGlobalLock) {
131                 final Task task = displayContent.findTaskForResizePoint(x, y);
132                 if (task != null) {
133                     if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
134                             task.preserveOrientationOnResize(), x, y)) {
135                         return;
136                     }
137                     try {
138                         mActivityManager.setFocusedTask(task.mTaskId);
139                     } catch (RemoteException e) {
140                     }
141                 }
142             }
143         });
144     }
145 
startPositioningLocked(WindowState win, boolean resize, boolean preserveOrientation, float startX, float startY)146     private boolean startPositioningLocked(WindowState win, boolean resize,
147             boolean preserveOrientation, float startX, float startY) {
148         if (DEBUG_TASK_POSITIONING)
149             Slog.d(TAG_WM, "startPositioningLocked: "
150                     + "win=" + win + ", resize=" + resize + ", preserveOrientation="
151                     + preserveOrientation + ", {" + startX + ", " + startY + "}");
152 
153         if (win == null || win.getAppToken() == null) {
154             Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
155             return false;
156         }
157         if (win.mInputChannel == null) {
158             Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
159                     + " probably being removed");
160             return false;
161         }
162 
163         final DisplayContent displayContent = win.getDisplayContent();
164         if (displayContent == null) {
165             Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
166             return false;
167         }
168         mPositioningDisplay = displayContent;
169 
170         mTaskPositioner = TaskPositioner.create(mService);
171 
172         // We need to grab the touch focus so that the touch events during the
173         // resizing/scrolling are not sent to the app. 'win' is the main window
174         // of the app, it may not have focus since there might be other windows
175         // on top (eg. a dialog window).
176         WindowState transferFocusFromWin = win;
177         if (displayContent.mCurrentFocus != null && displayContent.mCurrentFocus != win
178                 && displayContent.mCurrentFocus.mAppToken == win.mAppToken) {
179             transferFocusFromWin = displayContent.mCurrentFocus;
180         }
181         mTransferTouchFromToken = transferFocusFromWin.mInputChannel.getToken();
182         mTaskPositioner.register(displayContent);
183 
184         mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
185         return true;
186     }
187 
finishTaskPositioning(IWindow window)188     public void finishTaskPositioning(IWindow window) {
189         if (mTaskPositioner != null && mTaskPositioner.mClientCallback == window.asBinder()) {
190             finishTaskPositioning();
191         }
192     }
193 
finishTaskPositioning()194     void finishTaskPositioning() {
195         mHandler.post(() -> {
196             if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning");
197 
198             synchronized (mService.mGlobalLock) {
199                 cleanUpTaskPositioner();
200                 mPositioningDisplay = null;
201             }
202         });
203     }
204 
cleanUpTaskPositioner()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     }
216 }
217