blob: d7caa1a7b7955ec509de71a783f2f4e884c73290 [file] [log] [blame]
Wale Ogunwale65ebd952018-04-25 15:41:44 -07001/*
2 * Copyright (C) 2018 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.am;
18
19import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
20import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
21import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
22import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
23import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
24import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
25import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
26import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
27import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
28import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
29import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
30import static com.android.server.am.ActivityManagerService.ANIMATE;
31import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
32import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
33
34import android.app.ActivityManager;
35import android.app.IActivityTaskManager;
36import android.app.WindowConfiguration;
37import android.content.Context;
38import android.graphics.Rect;
39import android.os.Binder;
40import android.util.Slog;
41
42import com.android.server.SystemService;
43
44import java.util.ArrayList;
45import java.util.List;
46
47/**
48 * System service for managing activities and their containers (task, stacks, displays,... ).
49 *
50 * {@hide}
51 */
52public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
53 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_AM;
54 private static final String TAG_STACK = TAG + POSTFIX_STACK;
55
56 private Context mContext;
57 private ActivityManagerService mAm;
58 /* Global service lock used by the package the owns this service. */
59 Object mGlobalLock;
60 private ActivityStackSupervisor mStackSupervisor;
61
62 ActivityTaskManagerService(Context context) {
63 mContext = context;
64 }
65
66 // TODO: Will be converted to WM lock once transition is complete.
67 void setActivityManagerService(ActivityManagerService am) {
68 mAm = am;
69 mGlobalLock = mAm;
70 mStackSupervisor = mAm.mStackSupervisor;
71 }
72
73 public static final class Lifecycle extends SystemService {
74 private final ActivityTaskManagerService mService;
75
76 public Lifecycle(Context context) {
77 super(context);
78 mService = new ActivityTaskManagerService(context);
79 }
80
81 @Override
82 public void onStart() {
83 publishBinderService(Context.ACTIVITY_TASK_SERVICE, mService);
84 }
85
86 public ActivityTaskManagerService getService() {
87 return mService;
88 }
89 }
90
91 @Override
92 public void setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) {
93 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
94 setTaskWindowingModeSplitScreenPrimary(taskId, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
95 toTop, ANIMATE, null /* initialBounds */, true /* showRecents */);
96 return;
97 }
98 mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
99 synchronized (mGlobalLock) {
100 final long ident = Binder.clearCallingIdentity();
101 try {
102 final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
103 if (task == null) {
104 Slog.w(TAG, "setTaskWindowingMode: No task for id=" + taskId);
105 return;
106 }
107
108 if (DEBUG_STACK) Slog.d(TAG_STACK, "setTaskWindowingMode: moving task=" + taskId
109 + " to windowingMode=" + windowingMode + " toTop=" + toTop);
110
111 if (!task.isActivityTypeStandardOrUndefined()) {
112 throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
113 + " non-standard task " + taskId + " to windowing mode="
114 + windowingMode);
115 }
116
117 final ActivityStack stack = task.getStack();
118 if (toTop) {
119 stack.moveToFront("setTaskWindowingMode", task);
120 }
121 stack.setWindowingMode(windowingMode);
122 } finally {
123 Binder.restoreCallingIdentity(ident);
124 }
125 }
126 }
127
128 @Override
129 public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
130 return getFilteredTasks(maxNum, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED);
131 }
132
133 @Override
134 public List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
135 @WindowConfiguration.ActivityType int ignoreActivityType,
136 @WindowConfiguration.WindowingMode int ignoreWindowingMode) {
137 final int callingUid = Binder.getCallingUid();
138 ArrayList<ActivityManager.RunningTaskInfo> list = new ArrayList<>();
139
140 synchronized (mGlobalLock) {
141 if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum);
142
143 final boolean allowed = mAm.isGetTasksAllowed("getTasks", Binder.getCallingPid(),
144 callingUid);
145 mStackSupervisor.getRunningTasks(maxNum, list, ignoreActivityType,
146 ignoreWindowingMode, callingUid, allowed);
147 }
148
149 return list;
150 }
151
152 @Override
153 public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
154 mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
155 synchronized (mGlobalLock) {
156 final long ident = Binder.clearCallingIdentity();
157 try {
158 final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
159 if (task == null) {
160 Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId);
161 return;
162 }
163
164 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
165 + " to stackId=" + stackId + " toTop=" + toTop);
166
167 final ActivityStack stack = mStackSupervisor.getStack(stackId);
168 if (stack == null) {
169 throw new IllegalStateException(
170 "moveTaskToStack: No stack for stackId=" + stackId);
171 }
172 if (!stack.isActivityTypeStandardOrUndefined()) {
173 throw new IllegalArgumentException("moveTaskToStack: Attempt to move task "
174 + taskId + " to stack " + stackId);
175 }
176 if (stack.inSplitScreenPrimaryWindowingMode()) {
177 mAm.mWindowManager.setDockedStackCreateState(
178 SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
179 }
180 task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
181 "moveTaskToStack");
182 } finally {
183 Binder.restoreCallingIdentity(ident);
184 }
185 }
186 }
187
188 @Override
189 public void resizeStack(int stackId, Rect destBounds, boolean allowResizeInDockedMode,
190 boolean preserveWindows, boolean animate, int animationDuration) {
191 mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
192
193 final long ident = Binder.clearCallingIdentity();
194 try {
195 synchronized (mGlobalLock) {
196 if (animate) {
197 final PinnedActivityStack stack = mStackSupervisor.getStack(stackId);
198 if (stack == null) {
199 Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
200 return;
201 }
202 if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) {
203 throw new IllegalArgumentException("Stack: " + stackId
204 + " doesn't support animated resize.");
205 }
206 stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds,
207 animationDuration, false /* fromFullscreen */);
208 } else {
209 final ActivityStack stack = mStackSupervisor.getStack(stackId);
210 if (stack == null) {
211 Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
212 return;
213 }
214 mStackSupervisor.resizeStackLocked(stack, destBounds,
215 null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
216 preserveWindows, allowResizeInDockedMode, !DEFER_RESUME);
217 }
218 }
219 } finally {
220 Binder.restoreCallingIdentity(ident);
221 }
222 }
223
224 /**
225 * Moves the specified task to the primary-split-screen stack.
226 *
227 * @param taskId Id of task to move.
228 * @param createMode The mode the primary split screen stack should be created in if it doesn't
229 * exist already. See
230 * {@link android.app.ActivityTaskManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
231 * and
232 * {@link android.app.ActivityTaskManager#SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
233 * @param toTop If the task and stack should be moved to the top.
234 * @param animate Whether we should play an animation for the moving the task.
235 * @param initialBounds If the primary stack gets created, it will use these bounds for the
236 * stack. Pass {@code null} to use default bounds.
237 * @param showRecents If the recents activity should be shown on the other side of the task
238 * going into split-screen mode.
239 */
240 @Override
241 public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
242 boolean toTop, boolean animate, Rect initialBounds, boolean showRecents) {
243 mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
244 "setTaskWindowingModeSplitScreenPrimary()");
245 synchronized (mGlobalLock) {
246 final long ident = Binder.clearCallingIdentity();
247 try {
248 final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
249 if (task == null) {
250 Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
251 return false;
252 }
253 if (DEBUG_STACK) Slog.d(TAG_STACK,
254 "setTaskWindowingModeSplitScreenPrimary: moving task=" + taskId
255 + " to createMode=" + createMode + " toTop=" + toTop);
256 if (!task.isActivityTypeStandardOrUndefined()) {
257 throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
258 + " non-standard task " + taskId + " to split-screen windowing mode");
259 }
260
261 mAm.mWindowManager.setDockedStackCreateState(createMode, initialBounds);
262 final int windowingMode = task.getWindowingMode();
263 final ActivityStack stack = task.getStack();
264 if (toTop) {
265 stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
266 }
267 stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents,
268 false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */);
269 return windowingMode != task.getWindowingMode();
270 } finally {
271 Binder.restoreCallingIdentity(ident);
272 }
273 }
274 }
275
276 /**
277 * Removes stacks in the input windowing modes from the system if they are of activity type
278 * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
279 */
280 @Override
281 public void removeStacksInWindowingModes(int[] windowingModes) {
282 mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
283 "removeStacksInWindowingModes()");
284
285 synchronized (mGlobalLock) {
286 final long ident = Binder.clearCallingIdentity();
287 try {
288 mStackSupervisor.removeStacksInWindowingModes(windowingModes);
289 } finally {
290 Binder.restoreCallingIdentity(ident);
291 }
292 }
293 }
294
295 @Override
296 public void removeStacksWithActivityTypes(int[] activityTypes) {
297 mAm.enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
298 "removeStacksWithActivityTypes()");
299
300 synchronized (mGlobalLock) {
301 final long ident = Binder.clearCallingIdentity();
302 try {
303 mStackSupervisor.removeStacksWithActivityTypes(activityTypes);
304 } finally {
305 Binder.restoreCallingIdentity(ident);
306 }
307 }
308 }
309}