blob: b2f2863b8808f3b27323476e55114bcd6db83e1d [file] [log] [blame]
Keun-young Park4727da32016-05-31 10:00:51 -07001/*
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 */
16package com.android.car;
17
Yao, Yuxingd525de12019-05-06 15:11:48 -070018import static com.android.car.pm.CarPackageManagerService.BLOCKING_INTENT_EXTRA_DISPLAY_ID;
19
Sudheer Shankaa4f49aa2016-11-10 16:39:13 -080020import android.app.ActivityManager;
Keun-young Park4727da32016-05-31 10:00:51 -070021import android.app.ActivityManager.StackInfo;
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -080022import android.app.ActivityOptions;
Keun-young Park4727da32016-05-31 10:00:51 -070023import android.app.IActivityManager;
24import android.app.IProcessObserver;
Yorke Leec1265de2016-10-27 11:25:25 -070025import android.app.TaskStackListener;
Keun-young Park4727da32016-05-31 10:00:51 -070026import android.content.ComponentName;
27import android.content.Context;
28import android.content.Intent;
29import android.os.Handler;
30import android.os.HandlerThread;
31import android.os.Looper;
32import android.os.Message;
33import android.os.RemoteException;
34import android.os.UserHandle;
Yao Chened8609e2016-10-07 09:49:13 -070035import android.util.ArrayMap;
Keun-young Park4727da32016-05-31 10:00:51 -070036import android.util.ArraySet;
37import android.util.Log;
38import android.util.Pair;
39import android.util.SparseArray;
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -080040import android.view.Display;
Keun-young Park4727da32016-05-31 10:00:51 -070041
42import java.io.PrintWriter;
43import java.util.Arrays;
Keun-young Park4727da32016-05-31 10:00:51 -070044import java.util.LinkedList;
45import java.util.List;
46import java.util.Map;
Yao Chened8609e2016-10-07 09:49:13 -070047import java.util.Objects;
Keun-young Park4727da32016-05-31 10:00:51 -070048import java.util.Set;
49
50/**
51 * Service to monitor AMS for new Activity or Service launching.
52 */
53public class SystemActivityMonitoringService implements CarServiceBase {
54
55 /**
56 * Container to hold info on top task in an Activity stack
57 */
58 public static class TopTaskInfoContainer {
59 public final ComponentName topActivity;
60 public final int taskId;
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -080061 public final int displayId;
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -080062 public final int position;
Keun-young Park4727da32016-05-31 10:00:51 -070063 public final StackInfo stackInfo;
64
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -080065 private TopTaskInfoContainer(ComponentName topActivity, int taskId,
66 int displayId, int position, StackInfo stackInfo) {
Keun-young Park4727da32016-05-31 10:00:51 -070067 this.topActivity = topActivity;
68 this.taskId = taskId;
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -080069 this.displayId = displayId;
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -080070 this.position = position;
Keun-young Park4727da32016-05-31 10:00:51 -070071 this.stackInfo = stackInfo;
72 }
73
Yao Chened8609e2016-10-07 09:49:13 -070074 public boolean isMatching(TopTaskInfoContainer taskInfo) {
75 return taskInfo != null
76 && Objects.equals(this.topActivity, taskInfo.topActivity)
77 && this.taskId == taskInfo.taskId
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -080078 && this.displayId == taskInfo.displayId
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -080079 && this.position == taskInfo.position
Yao Chened8609e2016-10-07 09:49:13 -070080 && this.stackInfo.userId == taskInfo.stackInfo.userId;
Keun-young Park4727da32016-05-31 10:00:51 -070081 }
82
83 @Override
84 public String toString() {
85 return String.format(
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -080086 "TaskInfoContainer [topActivity=%s, taskId=%d, stackId=%d, userId=%d, "
87 + "displayId=%d, position=%d",
88 topActivity, taskId, stackInfo.stackId, stackInfo.userId, displayId, position);
Keun-young Park4727da32016-05-31 10:00:51 -070089 }
90 }
91
92 public interface ActivityLaunchListener {
93 /**
94 * Notify launch of activity.
95 * @param topTask Task information for what is currently launched.
96 */
97 void onActivityLaunch(TopTaskInfoContainer topTask);
98 }
99
Michal Palczewski7684dbb2018-11-13 18:36:06 -0800100 private static final int INVALID_STACK_ID = -1;
Keun-young Park4727da32016-05-31 10:00:51 -0700101 private final Context mContext;
102 private final IActivityManager mAm;
103 private final ProcessObserver mProcessObserver;
104 private final TaskListener mTaskListener;
105
106 private final HandlerThread mMonitorHandlerThread;
107 private final ActivityMonitorHandler mHandler;
108
Yao, Yuxingd525de12019-05-06 15:11:48 -0700109 /** K: display id, V: top task */
Keun-young Park4727da32016-05-31 10:00:51 -0700110 private final SparseArray<TopTaskInfoContainer> mTopTasks = new SparseArray<>();
111 /** K: uid, V : list of pid */
Yao Chened8609e2016-10-07 09:49:13 -0700112 private final Map<Integer, Set<Integer>> mForegroundUidPids = new ArrayMap<>();
Michal Palczewski7684dbb2018-11-13 18:36:06 -0800113 private int mFocusedStackId = INVALID_STACK_ID;
Keun-young Park4727da32016-05-31 10:00:51 -0700114 private ActivityLaunchListener mActivityLaunchListener;
115
116 public SystemActivityMonitoringService(Context context) {
117 mContext = context;
118 mMonitorHandlerThread = new HandlerThread(CarLog.TAG_AM);
119 mMonitorHandlerThread.start();
120 mHandler = new ActivityMonitorHandler(mMonitorHandlerThread.getLooper());
121 mProcessObserver = new ProcessObserver();
122 mTaskListener = new TaskListener();
Sudheer Shankaa4f49aa2016-11-10 16:39:13 -0800123 mAm = ActivityManager.getService();
Keun-young Park4727da32016-05-31 10:00:51 -0700124 // Monitoring both listeners are necessary as there are cases where one listener cannot
125 // monitor activity change.
126 try {
127 mAm.registerProcessObserver(mProcessObserver);
128 mAm.registerTaskStackListener(mTaskListener);
129 } catch (RemoteException e) {
130 Log.e(CarLog.TAG_AM, "cannot register activity monitoring", e);
131 throw new RuntimeException(e);
132 }
133 updateTasks();
134 }
135
136 @Override
137 public void init() {
138 }
139
140 @Override
141 public void release() {
142 }
143
144 @Override
145 public void dump(PrintWriter writer) {
146 writer.println("*SystemActivityMonitoringService*");
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800147 writer.println(" Top Tasks per display:");
Keun-young Park4727da32016-05-31 10:00:51 -0700148 synchronized (this) {
149 for (int i = 0; i < mTopTasks.size(); i++) {
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800150 int displayId = mTopTasks.keyAt(i);
Keun-young Park4727da32016-05-31 10:00:51 -0700151 TopTaskInfoContainer info = mTopTasks.valueAt(i);
152 if (info != null) {
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800153 writer.println("display id " + displayId + ": " + info);
Keun-young Park4727da32016-05-31 10:00:51 -0700154 }
155 }
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800156 writer.println(" Foreground uid-pids:");
Keun-young Park4727da32016-05-31 10:00:51 -0700157 for (Integer key : mForegroundUidPids.keySet()) {
158 Set<Integer> pids = mForegroundUidPids.get(key);
159 if (pids == null) {
160 continue;
161 }
162 writer.println("uid:" + key + ", pids:" + Arrays.toString(pids.toArray()));
163 }
164 writer.println(" focused stack:" + mFocusedStackId);
165 }
166 }
167
168 /**
169 * Block the current task: Launch new activity with given Intent and finish the current task.
170 * @param currentTask task to finish
171 * @param newActivityIntent Intent for new Activity
172 */
173 public void blockActivity(TopTaskInfoContainer currentTask, Intent newActivityIntent) {
174 mHandler.requestBlockActivity(currentTask, newActivityIntent);
175 }
176
177 public List<TopTaskInfoContainer> getTopTasks() {
178 LinkedList<TopTaskInfoContainer> tasks = new LinkedList<>();
179 synchronized (this) {
180 for (int i = 0; i < mTopTasks.size(); i++) {
Yao, Yuxing2646cff2019-04-23 17:01:26 -0700181 TopTaskInfoContainer topTask = mTopTasks.valueAt(i);
182 if (topTask == null) {
183 Log.e(CarLog.TAG_AM, "Top tasks contains null. Full content is: "
184 + mTopTasks.toString());
185 continue;
186 }
187 tasks.add(topTask);
Keun-young Park4727da32016-05-31 10:00:51 -0700188 }
189 }
190 return tasks;
191 }
192
193 public boolean isInForeground(int pid, int uid) {
194 synchronized (this) {
195 Set<Integer> pids = mForegroundUidPids.get(uid);
196 if (pids == null) {
197 return false;
198 }
199 if (pids.contains(pid)) {
200 return true;
201 }
202 }
203 return false;
204 }
205
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700206 /**
207 * Attempts to restart a task.
208 *
209 * <p>Restarts a task by sending an empty intent with flag
210 * {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} to its root activity. If the task does not exist,
211 * do nothing.
212 *
213 * @param taskId id of task to be restarted.
214 */
215 public void restartTask(int taskId) {
216 String rootActivityName = null;
217 int userId = 0;
218 try {
219 findRootActivityName:
220 for (StackInfo info : mAm.getAllStackInfos()) {
221 for (int i = 0; i < info.taskIds.length; i++) {
222 if (info.taskIds[i] == taskId) {
223 rootActivityName = info.taskNames[i];
224 userId = info.userId;
225 if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
226 Log.d(CarLog.TAG_AM, "Root activity is " + rootActivityName);
227 Log.d(CarLog.TAG_AM, "User id is " + userId);
228 }
229 // Break out of nested loop.
230 break findRootActivityName;
231 }
232 }
233 }
234 } catch (RemoteException e) {
235 Log.e(CarLog.TAG_AM, "Could not get stack info", e);
236 return;
237 }
238
239 if (rootActivityName == null) {
240 Log.e(CarLog.TAG_AM, "Could not find root activity with task id " + taskId);
241 return;
242 }
243
244 Intent rootActivityIntent = new Intent();
245 rootActivityIntent.setComponent(ComponentName.unflattenFromString(rootActivityName));
246 // Clear the task the root activity is running in and start it in a new task.
247 // Effectively restart root activity.
248 rootActivityIntent.addFlags(
249 Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
250
251 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
252 Log.i(CarLog.TAG_AM, "restarting root activity with user id " + userId);
253 }
254 mContext.startActivityAsUser(rootActivityIntent, new UserHandle(userId));
255 }
256
Keun-young Park4727da32016-05-31 10:00:51 -0700257 public void registerActivityLaunchListener(ActivityLaunchListener listener) {
258 synchronized (this) {
259 mActivityLaunchListener = listener;
260 }
261 }
262
263 private void updateTasks() {
264 List<StackInfo> infos;
265 try {
266 infos = mAm.getAllStackInfos();
267 } catch (RemoteException e) {
268 Log.e(CarLog.TAG_AM, "cannot getTasks", e);
269 return;
270 }
tadvana3b9ed202019-07-17 19:21:28 -0700271
272 if (infos == null) {
273 return;
274 }
275
Michal Palczewski7684dbb2018-11-13 18:36:06 -0800276 int focusedStackId = INVALID_STACK_ID;
Keun-young Park4727da32016-05-31 10:00:51 -0700277 try {
Wale Ogunwale9a000b92017-09-26 11:05:02 -0700278 // TODO(b/66955160): Someone on the Auto-team should probably re-work the code in the
279 // synchronized block below based on this new API.
280 final StackInfo focusedStackInfo = mAm.getFocusedStackInfo();
281 if (focusedStackInfo != null) {
282 focusedStackId = focusedStackInfo.stackId;
283 }
Keun-young Park4727da32016-05-31 10:00:51 -0700284 } catch (RemoteException e) {
285 Log.e(CarLog.TAG_AM, "cannot getFocusedStackId", e);
286 return;
287 }
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800288
289 SparseArray<TopTaskInfoContainer> topTasks = new SparseArray<>();
Keun-young Park4727da32016-05-31 10:00:51 -0700290 ActivityLaunchListener listener;
291 synchronized (this) {
292 listener = mActivityLaunchListener;
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700293
Keun-young Park4727da32016-05-31 10:00:51 -0700294 for (StackInfo info : infos) {
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800295 int displayId = info.displayId;
Keun-young Park4727da32016-05-31 10:00:51 -0700296 if (info.taskNames.length == 0 || !info.visible) { // empty stack or not shown
Keun-young Park4727da32016-05-31 10:00:51 -0700297 continue;
298 }
Yao Chened8609e2016-10-07 09:49:13 -0700299 TopTaskInfoContainer newTopTaskInfo = new TopTaskInfoContainer(
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800300 info.topActivity, info.taskIds[info.taskIds.length - 1],
301 info.displayId, info.position, info);
302 TopTaskInfoContainer currentTopTaskInfo = topTasks.get(displayId);
Yao Chened8609e2016-10-07 09:49:13 -0700303
Keun-young Park4727da32016-05-31 10:00:51 -0700304 if (currentTopTaskInfo == null ||
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800305 newTopTaskInfo.position > currentTopTaskInfo.position) {
306 topTasks.put(displayId, newTopTaskInfo);
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700307 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700308 Log.i(CarLog.TAG_AM, "Updating top task to: " + newTopTaskInfo);
Keun-young Park4727da32016-05-31 10:00:51 -0700309 }
310 }
311 }
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800312 // Assuming displays remains the same.
313 for (int i = 0; i < topTasks.size(); i++) {
Yao, Yuxing2646cff2019-04-23 17:01:26 -0700314 TopTaskInfoContainer topTask = topTasks.valueAt(i);
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700315
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800316 int displayId = topTasks.keyAt(i);
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700317 mTopTasks.put(displayId, topTask);
Michal Palczewski7684dbb2018-11-13 18:36:06 -0800318 }
Keun-young Park4727da32016-05-31 10:00:51 -0700319 }
320 if (listener != null) {
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700321 for (int i = 0; i < topTasks.size(); i++) {
322 TopTaskInfoContainer topTask = topTasks.valueAt(i);
323
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700324 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700325 Log.i(CarLog.TAG_AM, "Notifying about top task: " + topTask.toString());
Keun-young Park4727da32016-05-31 10:00:51 -0700326 }
327 listener.onActivityLaunch(topTask);
328 }
329 }
330 }
331
332 public StackInfo getFocusedStackForTopActivity(ComponentName activity) {
Keun-young Park4727da32016-05-31 10:00:51 -0700333 StackInfo focusedStack;
334 try {
Wale Ogunwale9a000b92017-09-26 11:05:02 -0700335 focusedStack = mAm.getFocusedStackInfo();
Keun-young Park4727da32016-05-31 10:00:51 -0700336 } catch (RemoteException e) {
337 Log.e(CarLog.TAG_AM, "cannot getFocusedStackId", e);
338 return null;
339 }
340 if (focusedStack.taskNames.length == 0) { // nothing in focused stack
341 return null;
342 }
343 ComponentName topActivity = ComponentName.unflattenFromString(
344 focusedStack.taskNames[focusedStack.taskNames.length - 1]);
345 if (topActivity.equals(activity)) {
346 return focusedStack;
347 } else {
348 return null;
349 }
350 }
351
352 private void handleForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
353 synchronized (this) {
354 if (foregroundActivities) {
355 Set<Integer> pids = mForegroundUidPids.get(uid);
356 if (pids == null) {
357 pids = new ArraySet<Integer>();
358 mForegroundUidPids.put(uid, pids);
359 }
360 pids.add(pid);
361 } else {
362 doHandlePidGoneLocked(pid, uid);
363 }
364 }
365 }
366
367 private void handleProcessDied(int pid, int uid) {
368 synchronized (this) {
369 doHandlePidGoneLocked(pid, uid);
370 }
371 }
372
373 private void doHandlePidGoneLocked(int pid, int uid) {
374 Set<Integer> pids = mForegroundUidPids.get(uid);
375 if (pids != null) {
376 pids.remove(pid);
377 if (pids.isEmpty()) {
378 mForegroundUidPids.remove(uid);
379 }
380 }
381 }
382
Ram Periathiruvadiffcdb842018-04-16 17:17:39 -0700383 /**
384 * block the current task with the provided new activity.
385 */
Keun-young Park4727da32016-05-31 10:00:51 -0700386 private void handleBlockActivity(TopTaskInfoContainer currentTask, Intent newActivityIntent) {
Yao, Yuxingd525de12019-05-06 15:11:48 -0700387 int displayId = newActivityIntent.getIntExtra(BLOCKING_INTENT_EXTRA_DISPLAY_ID,
388 Display.DEFAULT_DISPLAY);
389 if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
390 Log.d(CarLog.TAG_AM, "Launching blocking activity on display: " + displayId);
391 }
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -0800392
Yao, Yuxingd525de12019-05-06 15:11:48 -0700393 ActivityOptions options = ActivityOptions.makeBasic();
394 options.setLaunchDisplayId(displayId);
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -0800395 mContext.startActivityAsUser(newActivityIntent, options.toBundle(),
Keun-young Park4727da32016-05-31 10:00:51 -0700396 new UserHandle(currentTask.stackInfo.userId));
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700397 // Now make stack with new activity focused.
Keun-young Park4727da32016-05-31 10:00:51 -0700398 findTaskAndGrantFocus(newActivityIntent.getComponent());
Keun-young Park4727da32016-05-31 10:00:51 -0700399 }
400
401 private void findTaskAndGrantFocus(ComponentName activity) {
402 List<StackInfo> infos;
403 try {
404 infos = mAm.getAllStackInfos();
405 } catch (RemoteException e) {
406 Log.e(CarLog.TAG_AM, "cannot getTasks", e);
407 return;
408 }
409 for (StackInfo info : infos) {
410 if (info.taskNames.length == 0) {
411 continue;
412 }
413 ComponentName topActivity = ComponentName.unflattenFromString(
414 info.taskNames[info.taskNames.length - 1]);
415 if (activity.equals(topActivity)) {
416 try {
417 mAm.setFocusedStack(info.stackId);
418 } catch (RemoteException e) {
419 Log.e(CarLog.TAG_AM, "cannot setFocusedStack to stack:" + info.stackId, e);
420 }
421 return;
422 }
423 }
424 Log.i(CarLog.TAG_AM, "cannot give focus, cannot find Activity:" + activity);
425 }
426
427 private class ProcessObserver extends IProcessObserver.Stub {
428 @Override
429 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700430 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Keun-young Park4727da32016-05-31 10:00:51 -0700431 Log.i(CarLog.TAG_AM,
432 String.format("onForegroundActivitiesChanged uid %d pid %d fg %b",
433 uid, pid, foregroundActivities));
434 }
435 mHandler.requestForegroundActivitiesChanged(pid, uid, foregroundActivities);
436 }
437
438 @Override
Narayan Kamath4291a192019-03-15 18:49:29 +0000439 public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
440 }
441
442 @Override
Keun-young Park4727da32016-05-31 10:00:51 -0700443 public void onProcessDied(int pid, int uid) {
444 mHandler.requestProcessDied(pid, uid);
445 }
446 }
447
Yorke Leec1265de2016-10-27 11:25:25 -0700448 private class TaskListener extends TaskStackListener {
Keun-young Park4727da32016-05-31 10:00:51 -0700449 @Override
450 public void onTaskStackChanged() {
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700451 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Keun-young Park4727da32016-05-31 10:00:51 -0700452 Log.i(CarLog.TAG_AM, "onTaskStackChanged");
453 }
454 mHandler.requestUpdatingTask();
455 }
Keun-young Park4727da32016-05-31 10:00:51 -0700456 }
457
458 private class ActivityMonitorHandler extends Handler {
459 private static final int MSG_UPDATE_TASKS = 0;
460 private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 1;
461 private static final int MSG_PROCESS_DIED = 2;
462 private static final int MSG_BLOCK_ACTIVITY = 3;
463
464 private ActivityMonitorHandler(Looper looper) {
465 super(looper);
466 }
467
468 private void requestUpdatingTask() {
469 Message msg = obtainMessage(MSG_UPDATE_TASKS);
470 sendMessage(msg);
471 }
472
473 private void requestForegroundActivitiesChanged(int pid, int uid,
474 boolean foregroundActivities) {
475 Message msg = obtainMessage(MSG_FOREGROUND_ACTIVITIES_CHANGED, pid, uid,
476 Boolean.valueOf(foregroundActivities));
477 sendMessage(msg);
478 }
479
480 private void requestProcessDied(int pid, int uid) {
481 Message msg = obtainMessage(MSG_PROCESS_DIED, pid, uid);
482 sendMessage(msg);
483 }
484
485 private void requestBlockActivity(TopTaskInfoContainer currentTask,
486 Intent newActivityIntent) {
487 Message msg = obtainMessage(MSG_BLOCK_ACTIVITY,
488 new Pair<TopTaskInfoContainer, Intent>(currentTask, newActivityIntent));
489 sendMessage(msg);
490 }
491
492 @Override
493 public void handleMessage(Message msg) {
494 switch (msg.what) {
495 case MSG_UPDATE_TASKS:
496 updateTasks();
497 break;
498 case MSG_FOREGROUND_ACTIVITIES_CHANGED:
499 handleForegroundActivitiesChanged(msg.arg1, msg.arg2, (Boolean) msg.obj);
500 updateTasks();
501 break;
502 case MSG_PROCESS_DIED:
503 handleProcessDied(msg.arg1, msg.arg2);
504 break;
505 case MSG_BLOCK_ACTIVITY:
506 Pair<TopTaskInfoContainer, Intent> pair =
507 (Pair<TopTaskInfoContainer, Intent>) msg.obj;
508 handleBlockActivity(pair.first, pair.second);
509 break;
510 }
511 }
512 }
513}