2 * Copyright (C) 2017 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.shared.system;
19 import android.app.ActivityManager.RunningTaskInfo;
20 import android.app.ActivityManager.TaskSnapshot;
21 import android.app.ActivityTaskManager;
22 import android.app.IActivityManager;
23 import android.app.TaskStackListener;
24 import android.content.ComponentName;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.os.RemoteException;
30 import android.os.Trace;
31 import android.util.Log;
33 import com.android.systemui.shared.recents.model.ThumbnailData;
35 import java.util.ArrayList;
36 import java.util.List;
39 * Tracks all the task stack listeners
41 public class TaskStackChangeListeners extends TaskStackListener {
43 private static final String TAG = TaskStackChangeListeners.class.getSimpleName();
46 * List of {@link TaskStackChangeListener} registered from {@link #addListener}.
48 private final List<TaskStackChangeListener> mTaskStackListeners = new ArrayList<>();
49 private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>();
51 private final Handler mHandler;
52 private boolean mRegistered;
54 public TaskStackChangeListeners(Looper looper) {
55 mHandler = new H(looper);
58 public void addListener(IActivityManager am, TaskStackChangeListener listener) {
59 mTaskStackListeners.add(listener);
61 // Register mTaskStackListener to IActivityManager only once if needed.
63 ActivityTaskManager.getService().registerTaskStackListener(this);
65 } catch (Exception e) {
66 Log.w(TAG, "Failed to call registerTaskStackListener", e);
71 public void removeListener(TaskStackChangeListener listener) {
72 mTaskStackListeners.remove(listener);
73 if (mTaskStackListeners.isEmpty() && mRegistered) {
74 // Unregister mTaskStackListener once we have no more listeners
76 ActivityTaskManager.getService().unregisterTaskStackListener(this);
78 } catch (Exception e) {
79 Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
85 public void onTaskStackChanged() throws RemoteException {
86 // Call the task changed callback for the non-ui thread listeners first
87 synchronized (mTaskStackListeners) {
88 mTmpListeners.clear();
89 mTmpListeners.addAll(mTaskStackListeners);
91 for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
92 mTmpListeners.get(i).onTaskStackChangedBackground();
95 mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
96 mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
100 public void onActivityPinned(String packageName, int userId, int taskId, int stackId)
101 throws RemoteException {
102 mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
103 mHandler.obtainMessage(H.ON_ACTIVITY_PINNED,
104 new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget();
108 public void onActivityUnpinned() throws RemoteException {
109 mHandler.removeMessages(H.ON_ACTIVITY_UNPINNED);
110 mHandler.sendEmptyMessage(H.ON_ACTIVITY_UNPINNED);
114 public void onPinnedActivityRestartAttempt(boolean clearedTask)
115 throws RemoteException {
116 mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
117 mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0)
122 public void onPinnedStackAnimationStarted() throws RemoteException {
123 mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_STARTED);
124 mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_STARTED);
128 public void onPinnedStackAnimationEnded() throws RemoteException {
129 mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
130 mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
134 public void onActivityForcedResizable(String packageName, int taskId, int reason)
135 throws RemoteException {
136 mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
141 public void onActivityDismissingDockedStack() throws RemoteException {
142 mHandler.sendEmptyMessage(H.ON_ACTIVITY_DISMISSING_DOCKED_STACK);
146 public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
147 int requestedDisplayId) throws RemoteException {
148 mHandler.obtainMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED, requestedDisplayId,
150 taskInfo).sendToTarget();
154 public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
155 int requestedDisplayId) throws RemoteException {
156 mHandler.obtainMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
157 requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
161 public void onTaskProfileLocked(int taskId, int userId) throws RemoteException {
162 mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
166 public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException {
167 mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
171 public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
172 mHandler.obtainMessage(H.ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
176 public void onTaskRemoved(int taskId) throws RemoteException {
177 mHandler.obtainMessage(H.ON_TASK_REMOVED, taskId, 0).sendToTarget();
181 public void onTaskMovedToFront(RunningTaskInfo taskInfo)
182 throws RemoteException {
183 mHandler.obtainMessage(H.ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
187 public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) throws RemoteException {
188 mHandler.obtainMessage(H.ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
192 public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation)
193 throws RemoteException {
194 mHandler.obtainMessage(H.ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
195 requestedOrientation).sendToTarget();
199 public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
200 mHandler.obtainMessage(H.ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId, 0 /* unused */,
201 activityToken).sendToTarget();
205 public void onTaskDisplayChanged(int taskId, int newDisplayId) throws RemoteException {
206 mHandler.obtainMessage(H.ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
209 private final class H extends Handler {
210 private static final int ON_TASK_STACK_CHANGED = 1;
211 private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
212 private static final int ON_ACTIVITY_PINNED = 3;
213 private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4;
214 private static final int ON_PINNED_STACK_ANIMATION_ENDED = 5;
215 private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
216 private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
217 private static final int ON_TASK_PROFILE_LOCKED = 8;
218 private static final int ON_PINNED_STACK_ANIMATION_STARTED = 9;
219 private static final int ON_ACTIVITY_UNPINNED = 10;
220 private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 11;
221 private static final int ON_TASK_CREATED = 12;
222 private static final int ON_TASK_REMOVED = 13;
223 private static final int ON_TASK_MOVED_TO_FRONT = 14;
224 private static final int ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE = 15;
225 private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED = 16;
226 private static final int ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED = 17;
227 private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 18;
228 private static final int ON_TASK_DISPLAY_CHANGED = 19;
231 public H(Looper looper) {
236 public void handleMessage(Message msg) {
237 synchronized (mTaskStackListeners) {
239 case ON_TASK_STACK_CHANGED: {
240 Trace.beginSection("onTaskStackChanged");
241 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
242 mTaskStackListeners.get(i).onTaskStackChanged();
247 case ON_TASK_SNAPSHOT_CHANGED: {
248 Trace.beginSection("onTaskSnapshotChanged");
249 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
250 mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
251 new ThumbnailData((TaskSnapshot) msg.obj));
256 case ON_ACTIVITY_PINNED: {
257 final PinnedActivityInfo info = (PinnedActivityInfo) msg.obj;
258 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
259 mTaskStackListeners.get(i).onActivityPinned(
260 info.mPackageName, info.mUserId, info.mTaskId, info.mStackId);
264 case ON_ACTIVITY_UNPINNED: {
265 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
266 mTaskStackListeners.get(i).onActivityUnpinned();
270 case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
271 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
272 mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(
277 case ON_PINNED_STACK_ANIMATION_STARTED: {
278 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
279 mTaskStackListeners.get(i).onPinnedStackAnimationStarted();
283 case ON_PINNED_STACK_ANIMATION_ENDED: {
284 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
285 mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
289 case ON_ACTIVITY_FORCED_RESIZABLE: {
290 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
291 mTaskStackListeners.get(i).onActivityForcedResizable(
292 (String) msg.obj, msg.arg1, msg.arg2);
296 case ON_ACTIVITY_DISMISSING_DOCKED_STACK: {
297 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
298 mTaskStackListeners.get(i).onActivityDismissingDockedStack();
302 case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
303 final RunningTaskInfo info = (RunningTaskInfo) msg.obj;
304 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
305 mTaskStackListeners.get(i)
306 .onActivityLaunchOnSecondaryDisplayFailed(info);
310 case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED: {
311 final RunningTaskInfo info = (RunningTaskInfo) msg.obj;
312 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
313 mTaskStackListeners.get(i)
314 .onActivityLaunchOnSecondaryDisplayRerouted(info);
318 case ON_TASK_PROFILE_LOCKED: {
319 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
320 mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
324 case ON_TASK_CREATED: {
325 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
326 mTaskStackListeners.get(i).onTaskCreated(msg.arg1,
327 (ComponentName) msg.obj);
331 case ON_TASK_REMOVED: {
332 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
333 mTaskStackListeners.get(i).onTaskRemoved(msg.arg1);
337 case ON_TASK_MOVED_TO_FRONT: {
338 final RunningTaskInfo info = (RunningTaskInfo) msg.obj;
339 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
340 mTaskStackListeners.get(i).onTaskMovedToFront(info);
344 case ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE: {
345 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
346 mTaskStackListeners.get(i)
347 .onActivityRequestedOrientationChanged(msg.arg1, msg.arg2);
351 case ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED: {
352 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
353 mTaskStackListeners.get(i).onSizeCompatModeActivityChanged(
354 msg.arg1, (IBinder) msg.obj);
358 case ON_BACK_PRESSED_ON_TASK_ROOT: {
359 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
360 mTaskStackListeners.get(i).onBackPressedOnTaskRoot(
361 (RunningTaskInfo) msg.obj);
365 case ON_TASK_DISPLAY_CHANGED: {
366 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
367 mTaskStackListeners.get(i).onTaskDisplayChanged(msg.arg1, msg.arg2);
376 private static class PinnedActivityInfo {
377 final String mPackageName;
382 PinnedActivityInfo(String packageName, int userId, int taskId, int stackId) {
383 mPackageName = packageName;