1 /* 2 * Copyright (C) 2016 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 android.app.ActivityManager.TaskDescription; 20 import android.app.ActivityManager.TaskSnapshot; 21 import android.graphics.Rect; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.os.Message; 25 import android.util.EventLog; 26 import android.util.Slog; 27 import com.android.internal.annotations.VisibleForTesting; 28 29 import java.lang.ref.WeakReference; 30 31 import static com.android.server.EventLogTags.WM_TASK_CREATED; 32 import static com.android.server.wm.ConfigurationContainer.BOUNDS_CHANGE_NONE; 33 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; 34 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; 35 import static com.android.server.wm.WindowContainer.POSITION_TOP; 36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; 37 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 38 39 /** 40 * Controller for the task container. This is created by activity manager to link task records to 41 * the task container they use in window manager. 42 * 43 * Test class: {@link TaskWindowContainerControllerTests} 44 */ 45 public class TaskWindowContainerController 46 extends WindowContainerController<Task, TaskWindowContainerListener> { 47 48 private final int mTaskId; 49 private final H mHandler; 50 TaskWindowContainerController(int taskId, TaskWindowContainerListener listener, StackWindowController stackController, int userId, Rect bounds, int resizeMode, boolean supportsPictureInPicture, boolean toTop, boolean showForAllUsers, TaskDescription taskDescription)51 public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener, 52 StackWindowController stackController, int userId, Rect bounds, int resizeMode, 53 boolean supportsPictureInPicture, boolean toTop, boolean showForAllUsers, 54 TaskDescription taskDescription) { 55 this(taskId, listener, stackController, userId, bounds, resizeMode, 56 supportsPictureInPicture, toTop, showForAllUsers, taskDescription, 57 WindowManagerService.getInstance()); 58 } 59 TaskWindowContainerController(int taskId, TaskWindowContainerListener listener, StackWindowController stackController, int userId, Rect bounds, int resizeMode, boolean supportsPictureInPicture, boolean toTop, boolean showForAllUsers, TaskDescription taskDescription, WindowManagerService service)60 public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener, 61 StackWindowController stackController, int userId, Rect bounds, int resizeMode, 62 boolean supportsPictureInPicture, boolean toTop, boolean showForAllUsers, 63 TaskDescription taskDescription, WindowManagerService service) { 64 super(listener, service); 65 mTaskId = taskId; 66 mHandler = new H(new WeakReference<>(this), service.mH.getLooper()); 67 68 synchronized(mWindowMap) { 69 if (DEBUG_STACK) Slog.i(TAG_WM, "TaskWindowContainerController: taskId=" + taskId 70 + " stack=" + stackController + " bounds=" + bounds); 71 72 final TaskStack stack = stackController.mContainer; 73 if (stack == null) { 74 throw new IllegalArgumentException("TaskWindowContainerController: invalid stack=" 75 + stackController); 76 } 77 EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId); 78 final Task task = createTask(taskId, stack, userId, resizeMode, 79 supportsPictureInPicture, taskDescription); 80 final int position = toTop ? POSITION_TOP : POSITION_BOTTOM; 81 // We only want to move the parents to the parents if we are creating this task at the 82 // top of its stack. 83 stack.addTask(task, position, showForAllUsers, toTop /* moveParents */); 84 } 85 } 86 87 @VisibleForTesting createTask(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture, TaskDescription taskDescription)88 Task createTask(int taskId, TaskStack stack, int userId, int resizeMode, 89 boolean supportsPictureInPicture, TaskDescription taskDescription) { 90 return new Task(taskId, stack, userId, mService, resizeMode, supportsPictureInPicture, 91 taskDescription, this); 92 } 93 94 @Override removeContainer()95 public void removeContainer() { 96 synchronized(mWindowMap) { 97 if (mContainer == null) { 98 if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + mTaskId); 99 return; 100 } 101 mContainer.removeIfPossible(); 102 super.removeContainer(); 103 } 104 } 105 positionChildAtTop(AppWindowContainerController childController)106 public void positionChildAtTop(AppWindowContainerController childController) { 107 positionChildAt(childController, POSITION_TOP); 108 } 109 positionChildAt(AppWindowContainerController childController, int position)110 public void positionChildAt(AppWindowContainerController childController, int position) { 111 synchronized(mService.mWindowMap) { 112 final AppWindowToken aToken = childController.mContainer; 113 if (aToken == null) { 114 Slog.w(TAG_WM, 115 "Attempted to position of non-existing app : " + childController); 116 return; 117 } 118 119 final Task task = mContainer; 120 if (task == null) { 121 throw new IllegalArgumentException("positionChildAt: invalid task=" + this); 122 } 123 task.positionChildAt(position, aToken, false /* includeParents */); 124 } 125 } 126 reparent(StackWindowController stackController, int position, boolean moveParents)127 public void reparent(StackWindowController stackController, int position, boolean moveParents) { 128 synchronized (mWindowMap) { 129 if (DEBUG_STACK) Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId 130 + " to stack=" + stackController + " at " + position); 131 if (mContainer == null) { 132 if (DEBUG_STACK) Slog.i(TAG_WM, 133 "reparent: could not find taskId=" + mTaskId); 134 return; 135 } 136 final TaskStack stack = stackController.mContainer; 137 if (stack == null) { 138 throw new IllegalArgumentException("reparent: could not find stack=" 139 + stackController); 140 } 141 mContainer.reparent(stack, position, moveParents); 142 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); 143 } 144 } 145 setResizeable(int resizeMode)146 public void setResizeable(int resizeMode) { 147 synchronized (mWindowMap) { 148 if (mContainer != null) { 149 mContainer.setResizeable(resizeMode); 150 } 151 } 152 } 153 resize(boolean relayout, boolean forced)154 public void resize(boolean relayout, boolean forced) { 155 synchronized (mWindowMap) { 156 if (mContainer == null) { 157 throw new IllegalArgumentException("resizeTask: taskId " + mTaskId + " not found."); 158 } 159 160 if (mContainer.setBounds(mContainer.getOverrideBounds(), forced) != BOUNDS_CHANGE_NONE 161 && relayout) { 162 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); 163 } 164 } 165 } 166 getBounds(Rect bounds)167 public void getBounds(Rect bounds) { 168 synchronized (mWindowMap) { 169 if (mContainer != null) { 170 mContainer.getBounds(bounds); 171 return; 172 } 173 bounds.setEmpty(); 174 } 175 } 176 177 /** 178 * Puts this task into docked drag resizing mode. See {@link DragResizeMode}. 179 * 180 * @param resizing Whether to put the task into drag resize mode. 181 */ setTaskDockedResizing(boolean resizing)182 public void setTaskDockedResizing(boolean resizing) { 183 synchronized (mWindowMap) { 184 if (mContainer == null) { 185 Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + mTaskId + " not found."); 186 return; 187 } 188 mContainer.setDragResizing(resizing, DRAG_RESIZE_MODE_DOCKED_DIVIDER); 189 } 190 } 191 cancelWindowTransition()192 public void cancelWindowTransition() { 193 synchronized (mWindowMap) { 194 if (mContainer == null) { 195 Slog.w(TAG_WM, "cancelWindowTransition: taskId " + mTaskId + " not found."); 196 return; 197 } 198 mContainer.cancelTaskWindowTransition(); 199 } 200 } 201 setTaskDescription(TaskDescription taskDescription)202 public void setTaskDescription(TaskDescription taskDescription) { 203 synchronized (mWindowMap) { 204 if (mContainer == null) { 205 Slog.w(TAG_WM, "setTaskDescription: taskId " + mTaskId + " not found."); 206 return; 207 } 208 mContainer.setTaskDescription(taskDescription); 209 } 210 } 211 reportSnapshotChanged(TaskSnapshot snapshot)212 void reportSnapshotChanged(TaskSnapshot snapshot) { 213 mHandler.obtainMessage(H.REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget(); 214 } 215 requestResize(Rect bounds, int resizeMode)216 void requestResize(Rect bounds, int resizeMode) { 217 mHandler.obtainMessage(H.REQUEST_RESIZE, resizeMode, 0, bounds).sendToTarget(); 218 } 219 220 @Override toString()221 public String toString() { 222 return "{TaskWindowContainerController taskId=" + mTaskId + "}"; 223 } 224 225 private static final class H extends Handler { 226 227 static final int REPORT_SNAPSHOT_CHANGED = 0; 228 static final int REQUEST_RESIZE = 1; 229 230 private final WeakReference<TaskWindowContainerController> mController; 231 H(WeakReference<TaskWindowContainerController> controller, Looper looper)232 H(WeakReference<TaskWindowContainerController> controller, Looper looper) { 233 super(looper); 234 mController = controller; 235 } 236 237 @Override handleMessage(Message msg)238 public void handleMessage(Message msg) { 239 final TaskWindowContainerController controller = mController.get(); 240 final TaskWindowContainerListener listener = (controller != null) 241 ? controller.mListener : null; 242 if (listener == null) { 243 return; 244 } 245 switch (msg.what) { 246 case REPORT_SNAPSHOT_CHANGED: 247 listener.onSnapshotChanged((TaskSnapshot) msg.obj); 248 break; 249 case REQUEST_RESIZE: 250 listener.requestResize((Rect) msg.obj, msg.arg1); 251 break; 252 } 253 } 254 } 255 } 256