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