blob: d192727c0123bbf13ae90e137a0366e8c5ee43e4 [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 }
Michal Palczewski7684dbb2018-11-13 18:36:06 -0800271 int focusedStackId = INVALID_STACK_ID;
Keun-young Park4727da32016-05-31 10:00:51 -0700272 try {
Wale Ogunwale9a000b92017-09-26 11:05:02 -0700273 // TODO(b/66955160): Someone on the Auto-team should probably re-work the code in the
274 // synchronized block below based on this new API.
275 final StackInfo focusedStackInfo = mAm.getFocusedStackInfo();
276 if (focusedStackInfo != null) {
277 focusedStackId = focusedStackInfo.stackId;
278 }
Keun-young Park4727da32016-05-31 10:00:51 -0700279 } catch (RemoteException e) {
280 Log.e(CarLog.TAG_AM, "cannot getFocusedStackId", e);
281 return;
282 }
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800283
284 SparseArray<TopTaskInfoContainer> topTasks = new SparseArray<>();
Keun-young Park4727da32016-05-31 10:00:51 -0700285 ActivityLaunchListener listener;
286 synchronized (this) {
287 listener = mActivityLaunchListener;
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700288
Keun-young Park4727da32016-05-31 10:00:51 -0700289 for (StackInfo info : infos) {
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800290 int displayId = info.displayId;
Keun-young Park4727da32016-05-31 10:00:51 -0700291 if (info.taskNames.length == 0 || !info.visible) { // empty stack or not shown
Keun-young Park4727da32016-05-31 10:00:51 -0700292 continue;
293 }
Yao Chened8609e2016-10-07 09:49:13 -0700294 TopTaskInfoContainer newTopTaskInfo = new TopTaskInfoContainer(
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800295 info.topActivity, info.taskIds[info.taskIds.length - 1],
296 info.displayId, info.position, info);
297 TopTaskInfoContainer currentTopTaskInfo = topTasks.get(displayId);
Yao Chened8609e2016-10-07 09:49:13 -0700298
Keun-young Park4727da32016-05-31 10:00:51 -0700299 if (currentTopTaskInfo == null ||
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800300 newTopTaskInfo.position > currentTopTaskInfo.position) {
301 topTasks.put(displayId, newTopTaskInfo);
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700302 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700303 Log.i(CarLog.TAG_AM, "Updating top task to: " + newTopTaskInfo);
Keun-young Park4727da32016-05-31 10:00:51 -0700304 }
305 }
306 }
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800307 // Assuming displays remains the same.
308 for (int i = 0; i < topTasks.size(); i++) {
Yao, Yuxing2646cff2019-04-23 17:01:26 -0700309 TopTaskInfoContainer topTask = topTasks.valueAt(i);
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700310
Yao, Yuxing4ddb2c62019-02-04 11:26:46 -0800311 int displayId = topTasks.keyAt(i);
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700312 mTopTasks.put(displayId, topTask);
Michal Palczewski7684dbb2018-11-13 18:36:06 -0800313 }
Keun-young Park4727da32016-05-31 10:00:51 -0700314 }
315 if (listener != null) {
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700316 for (int i = 0; i < topTasks.size(); i++) {
317 TopTaskInfoContainer topTask = topTasks.valueAt(i);
318
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700319 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Yao, Yuxingf4ed5282019-04-09 13:37:59 -0700320 Log.i(CarLog.TAG_AM, "Notifying about top task: " + topTask.toString());
Keun-young Park4727da32016-05-31 10:00:51 -0700321 }
322 listener.onActivityLaunch(topTask);
323 }
324 }
325 }
326
327 public StackInfo getFocusedStackForTopActivity(ComponentName activity) {
Keun-young Park4727da32016-05-31 10:00:51 -0700328 StackInfo focusedStack;
329 try {
Wale Ogunwale9a000b92017-09-26 11:05:02 -0700330 focusedStack = mAm.getFocusedStackInfo();
Keun-young Park4727da32016-05-31 10:00:51 -0700331 } catch (RemoteException e) {
332 Log.e(CarLog.TAG_AM, "cannot getFocusedStackId", e);
333 return null;
334 }
335 if (focusedStack.taskNames.length == 0) { // nothing in focused stack
336 return null;
337 }
338 ComponentName topActivity = ComponentName.unflattenFromString(
339 focusedStack.taskNames[focusedStack.taskNames.length - 1]);
340 if (topActivity.equals(activity)) {
341 return focusedStack;
342 } else {
343 return null;
344 }
345 }
346
347 private void handleForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
348 synchronized (this) {
349 if (foregroundActivities) {
350 Set<Integer> pids = mForegroundUidPids.get(uid);
351 if (pids == null) {
352 pids = new ArraySet<Integer>();
353 mForegroundUidPids.put(uid, pids);
354 }
355 pids.add(pid);
356 } else {
357 doHandlePidGoneLocked(pid, uid);
358 }
359 }
360 }
361
362 private void handleProcessDied(int pid, int uid) {
363 synchronized (this) {
364 doHandlePidGoneLocked(pid, uid);
365 }
366 }
367
368 private void doHandlePidGoneLocked(int pid, int uid) {
369 Set<Integer> pids = mForegroundUidPids.get(uid);
370 if (pids != null) {
371 pids.remove(pid);
372 if (pids.isEmpty()) {
373 mForegroundUidPids.remove(uid);
374 }
375 }
376 }
377
Ram Periathiruvadiffcdb842018-04-16 17:17:39 -0700378 /**
379 * block the current task with the provided new activity.
380 */
Keun-young Park4727da32016-05-31 10:00:51 -0700381 private void handleBlockActivity(TopTaskInfoContainer currentTask, Intent newActivityIntent) {
Yao, Yuxingd525de12019-05-06 15:11:48 -0700382 int displayId = newActivityIntent.getIntExtra(BLOCKING_INTENT_EXTRA_DISPLAY_ID,
383 Display.DEFAULT_DISPLAY);
384 if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
385 Log.d(CarLog.TAG_AM, "Launching blocking activity on display: " + displayId);
386 }
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -0800387
Yao, Yuxingd525de12019-05-06 15:11:48 -0700388 ActivityOptions options = ActivityOptions.makeBasic();
389 options.setLaunchDisplayId(displayId);
Yao, Yuxingcfcc59f2019-03-05 16:35:47 -0800390 mContext.startActivityAsUser(newActivityIntent, options.toBundle(),
Keun-young Park4727da32016-05-31 10:00:51 -0700391 new UserHandle(currentTask.stackInfo.userId));
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700392 // Now make stack with new activity focused.
Keun-young Park4727da32016-05-31 10:00:51 -0700393 findTaskAndGrantFocus(newActivityIntent.getComponent());
Keun-young Park4727da32016-05-31 10:00:51 -0700394 }
395
396 private void findTaskAndGrantFocus(ComponentName activity) {
397 List<StackInfo> infos;
398 try {
399 infos = mAm.getAllStackInfos();
400 } catch (RemoteException e) {
401 Log.e(CarLog.TAG_AM, "cannot getTasks", e);
402 return;
403 }
404 for (StackInfo info : infos) {
405 if (info.taskNames.length == 0) {
406 continue;
407 }
408 ComponentName topActivity = ComponentName.unflattenFromString(
409 info.taskNames[info.taskNames.length - 1]);
410 if (activity.equals(topActivity)) {
411 try {
412 mAm.setFocusedStack(info.stackId);
413 } catch (RemoteException e) {
414 Log.e(CarLog.TAG_AM, "cannot setFocusedStack to stack:" + info.stackId, e);
415 }
416 return;
417 }
418 }
419 Log.i(CarLog.TAG_AM, "cannot give focus, cannot find Activity:" + activity);
420 }
421
422 private class ProcessObserver extends IProcessObserver.Stub {
423 @Override
424 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700425 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Keun-young Park4727da32016-05-31 10:00:51 -0700426 Log.i(CarLog.TAG_AM,
427 String.format("onForegroundActivitiesChanged uid %d pid %d fg %b",
428 uid, pid, foregroundActivities));
429 }
430 mHandler.requestForegroundActivitiesChanged(pid, uid, foregroundActivities);
431 }
432
433 @Override
Narayan Kamath4291a192019-03-15 18:49:29 +0000434 public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
435 }
436
437 @Override
Keun-young Park4727da32016-05-31 10:00:51 -0700438 public void onProcessDied(int pid, int uid) {
439 mHandler.requestProcessDied(pid, uid);
440 }
441 }
442
Yorke Leec1265de2016-10-27 11:25:25 -0700443 private class TaskListener extends TaskStackListener {
Keun-young Park4727da32016-05-31 10:00:51 -0700444 @Override
445 public void onTaskStackChanged() {
Yao, Yuxingd1d6a372018-05-08 10:37:43 -0700446 if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Keun-young Park4727da32016-05-31 10:00:51 -0700447 Log.i(CarLog.TAG_AM, "onTaskStackChanged");
448 }
449 mHandler.requestUpdatingTask();
450 }
Keun-young Park4727da32016-05-31 10:00:51 -0700451 }
452
453 private class ActivityMonitorHandler extends Handler {
454 private static final int MSG_UPDATE_TASKS = 0;
455 private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 1;
456 private static final int MSG_PROCESS_DIED = 2;
457 private static final int MSG_BLOCK_ACTIVITY = 3;
458
459 private ActivityMonitorHandler(Looper looper) {
460 super(looper);
461 }
462
463 private void requestUpdatingTask() {
464 Message msg = obtainMessage(MSG_UPDATE_TASKS);
465 sendMessage(msg);
466 }
467
468 private void requestForegroundActivitiesChanged(int pid, int uid,
469 boolean foregroundActivities) {
470 Message msg = obtainMessage(MSG_FOREGROUND_ACTIVITIES_CHANGED, pid, uid,
471 Boolean.valueOf(foregroundActivities));
472 sendMessage(msg);
473 }
474
475 private void requestProcessDied(int pid, int uid) {
476 Message msg = obtainMessage(MSG_PROCESS_DIED, pid, uid);
477 sendMessage(msg);
478 }
479
480 private void requestBlockActivity(TopTaskInfoContainer currentTask,
481 Intent newActivityIntent) {
482 Message msg = obtainMessage(MSG_BLOCK_ACTIVITY,
483 new Pair<TopTaskInfoContainer, Intent>(currentTask, newActivityIntent));
484 sendMessage(msg);
485 }
486
487 @Override
488 public void handleMessage(Message msg) {
489 switch (msg.what) {
490 case MSG_UPDATE_TASKS:
491 updateTasks();
492 break;
493 case MSG_FOREGROUND_ACTIVITIES_CHANGED:
494 handleForegroundActivitiesChanged(msg.arg1, msg.arg2, (Boolean) msg.obj);
495 updateTasks();
496 break;
497 case MSG_PROCESS_DIED:
498 handleProcessDied(msg.arg1, msg.arg2);
499 break;
500 case MSG_BLOCK_ACTIVITY:
501 Pair<TopTaskInfoContainer, Intent> pair =
502 (Pair<TopTaskInfoContainer, Intent>) msg.obj;
503 handleBlockActivity(pair.first, pair.second);
504 break;
505 }
506 }
507 }
508}