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