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.IActivityManager; 24 import android.os.RemoteException; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.util.Slog; 28 import android.view.Display; 29 import android.view.IWindow; 30 import com.android.internal.annotations.GuardedBy; 31 import com.android.server.input.InputManagerService; 32 import com.android.server.input.InputWindowHandle; 33 34 /** 35 * Controller for task positioning by drag. 36 */ 37 class TaskPositioningController { 38 private final WindowManagerService mService; 39 private final InputManagerService mInputManager; 40 private final InputMonitor mInputMonitor; 41 private final IActivityManager mActivityManager; 42 private final Handler mHandler; 43 44 @GuardedBy("WindowManagerSerivce.mWindowMap") 45 private @Nullable TaskPositioner mTaskPositioner; 46 isPositioningLocked()47 boolean isPositioningLocked() { 48 return mTaskPositioner != null; 49 } 50 getDragWindowHandleLocked()51 InputWindowHandle getDragWindowHandleLocked() { 52 return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null; 53 } 54 TaskPositioningController(WindowManagerService service, InputManagerService inputManager, InputMonitor inputMonitor, IActivityManager activityManager, Looper looper)55 TaskPositioningController(WindowManagerService service, InputManagerService inputManager, 56 InputMonitor inputMonitor, IActivityManager activityManager, Looper looper) { 57 mService = service; 58 mInputMonitor = inputMonitor; 59 mInputManager = inputManager; 60 mActivityManager = activityManager; 61 mHandler = new Handler(looper); 62 } 63 startMovingTask(IWindow window, float startX, float startY)64 boolean startMovingTask(IWindow window, float startX, float startY) { 65 WindowState win = null; 66 synchronized (mService.mWindowMap) { 67 win = mService.windowForClientLocked(null, window, false); 68 // win shouldn't be null here, pass it down to startPositioningLocked 69 // to get warning if it's null. 70 if (!startPositioningLocked( 71 win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) { 72 return false; 73 } 74 } 75 try { 76 mActivityManager.setFocusedTask(win.getTask().mTaskId); 77 } catch(RemoteException e) {} 78 return true; 79 } 80 handleTapOutsideTask(DisplayContent displayContent, int x, int y)81 void handleTapOutsideTask(DisplayContent displayContent, int x, int y) { 82 mHandler.post(() -> { 83 int taskId = -1; 84 synchronized (mService.mWindowMap) { 85 final Task task = displayContent.findTaskForResizePoint(x, y); 86 if (task != null) { 87 if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/, 88 task.preserveOrientationOnResize(), x, y)) { 89 return; 90 } 91 taskId = task.mTaskId; 92 } else { 93 taskId = displayContent.taskIdFromPoint(x, y); 94 } 95 } 96 if (taskId >= 0) { 97 try { 98 mActivityManager.setFocusedTask(taskId); 99 } catch (RemoteException e) { 100 } 101 } 102 }); 103 } 104 startPositioningLocked(WindowState win, boolean resize, boolean preserveOrientation, float startX, float startY)105 private boolean startPositioningLocked(WindowState win, boolean resize, 106 boolean preserveOrientation, float startX, float startY) { 107 if (DEBUG_TASK_POSITIONING) 108 Slog.d(TAG_WM, "startPositioningLocked: " 109 + "win=" + win + ", resize=" + resize + ", preserveOrientation=" 110 + preserveOrientation + ", {" + startX + ", " + startY + "}"); 111 112 if (win == null || win.getAppToken() == null) { 113 Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win); 114 return false; 115 } 116 if (win.mInputChannel == null) { 117 Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, " 118 + " probably being removed"); 119 return false; 120 } 121 122 final DisplayContent displayContent = win.getDisplayContent(); 123 if (displayContent == null) { 124 Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win); 125 return false; 126 } 127 128 Display display = displayContent.getDisplay(); 129 mTaskPositioner = TaskPositioner.create(mService); 130 mTaskPositioner.register(displayContent); 131 mInputMonitor.updateInputWindowsLw(true /*force*/); 132 133 // We need to grab the touch focus so that the touch events during the 134 // resizing/scrolling are not sent to the app. 'win' is the main window 135 // of the app, it may not have focus since there might be other windows 136 // on top (eg. a dialog window). 137 WindowState transferFocusFromWin = win; 138 if (mService.mCurrentFocus != null && mService.mCurrentFocus != win 139 && mService.mCurrentFocus.mAppToken == win.mAppToken) { 140 transferFocusFromWin = mService.mCurrentFocus; 141 } 142 if (!mInputManager.transferTouchFocus( 143 transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) { 144 Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus"); 145 mTaskPositioner.unregister(); 146 mTaskPositioner = null; 147 mInputMonitor.updateInputWindowsLw(true /*force*/); 148 return false; 149 } 150 151 mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY); 152 return true; 153 } 154 finishTaskPositioning()155 void finishTaskPositioning() { 156 mHandler.post(() -> { 157 if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning"); 158 159 synchronized (mService.mWindowMap) { 160 if (mTaskPositioner != null) { 161 mTaskPositioner.unregister(); 162 mTaskPositioner = null; 163 mInputMonitor.updateInputWindowsLw(true /*force*/); 164 } 165 } 166 }); 167 } 168 } 169