1 /* 2 * Copyright (C) 2017 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 17 package com.android.systemui.shared.system; 18 19 import android.app.ActivityManager.TaskSnapshot; 20 import android.app.IActivityManager; 21 import android.app.TaskStackListener; 22 import android.content.ComponentName; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.os.Message; 26 import android.os.RemoteException; 27 import android.os.Trace; 28 import android.util.Log; 29 30 import com.android.systemui.shared.recents.model.ThumbnailData; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 35 /** 36 * Tracks all the task stack listeners 37 */ 38 public class TaskStackChangeListeners extends TaskStackListener { 39 40 private static final String TAG = TaskStackChangeListeners.class.getSimpleName(); 41 42 /** 43 * List of {@link TaskStackChangeListener} registered from {@link #addListener}. 44 */ 45 private final List<TaskStackChangeListener> mTaskStackListeners = new ArrayList<>(); 46 private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>(); 47 48 private final Handler mHandler; 49 private boolean mRegistered; 50 51 public TaskStackChangeListeners(Looper looper) { 52 mHandler = new H(looper); 53 } 54 55 public void addListener(IActivityManager am, TaskStackChangeListener listener) { 56 mTaskStackListeners.add(listener); 57 if (!mRegistered) { 58 // Register mTaskStackListener to IActivityManager only once if needed. 59 try { 60 am.registerTaskStackListener(this); 61 mRegistered = true; 62 } catch (Exception e) { 63 Log.w(TAG, "Failed to call registerTaskStackListener", e); 64 } 65 } 66 } 67 68 public void removeListener(TaskStackChangeListener listener) { 69 mTaskStackListeners.remove(listener); 70 } 71 72 @Override 73 public void onTaskStackChanged() throws RemoteException { 74 // Call the task changed callback for the non-ui thread listeners first 75 synchronized (mTaskStackListeners) { 76 mTmpListeners.clear(); 77 mTmpListeners.addAll(mTaskStackListeners); 78 } 79 for (int i = mTmpListeners.size() - 1; i >= 0; i--) { 80 mTmpListeners.get(i).onTaskStackChangedBackground(); 81 } 82 83 mHandler.removeMessages(H.ON_TASK_STACK_CHANGED); 84 mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED); 85 } 86 87 @Override 88 public void onActivityPinned(String packageName, int userId, int taskId, int stackId) 89 throws RemoteException { 90 mHandler.removeMessages(H.ON_ACTIVITY_PINNED); 91 mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, 92 new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget(); 93 } 94 95 @Override 96 public void onActivityUnpinned() throws RemoteException { 97 mHandler.removeMessages(H.ON_ACTIVITY_UNPINNED); 98 mHandler.sendEmptyMessage(H.ON_ACTIVITY_UNPINNED); 99 } 100 101 @Override 102 public void onPinnedActivityRestartAttempt(boolean clearedTask) 103 throws RemoteException{ 104 mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT); 105 mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0) 106 .sendToTarget(); 107 } 108 109 @Override 110 public void onPinnedStackAnimationStarted() throws RemoteException { 111 mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_STARTED); 112 mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_STARTED); 113 } 114 115 @Override 116 public void onPinnedStackAnimationEnded() throws RemoteException { 117 mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED); 118 mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED); 119 } 120 121 @Override 122 public void onActivityForcedResizable(String packageName, int taskId, int reason) 123 throws RemoteException { 124 mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName) 125 .sendToTarget(); 126 } 127 128 @Override 129 public void onActivityDismissingDockedStack() throws RemoteException { 130 mHandler.sendEmptyMessage(H.ON_ACTIVITY_DISMISSING_DOCKED_STACK); 131 } 132 133 @Override 134 public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException { 135 mHandler.sendEmptyMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED); 136 } 137 138 @Override 139 public void onTaskProfileLocked(int taskId, int userId) throws RemoteException { 140 mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget(); 141 } 142 143 @Override 144 public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException { 145 mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget(); 146 } 147 148 @Override 149 public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException { 150 mHandler.obtainMessage(H.ON_TASK_CREATED, taskId, 0, componentName).sendToTarget(); 151 } 152 153 @Override 154 public void onTaskRemoved(int taskId) throws RemoteException { 155 mHandler.obtainMessage(H.ON_TASK_REMOVED, taskId, 0).sendToTarget(); 156 } 157 158 @Override 159 public void onTaskMovedToFront(int taskId) throws RemoteException { 160 mHandler.obtainMessage(H.ON_TASK_MOVED_TO_FRONT, taskId, 0).sendToTarget(); 161 } 162 163 @Override 164 public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) 165 throws RemoteException { 166 mHandler.obtainMessage(H.ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId, 167 requestedOrientation).sendToTarget(); 168 } 169 170 private final class H extends Handler { 171 private static final int ON_TASK_STACK_CHANGED = 1; 172 private static final int ON_TASK_SNAPSHOT_CHANGED = 2; 173 private static final int ON_ACTIVITY_PINNED = 3; 174 private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4; 175 private static final int ON_PINNED_STACK_ANIMATION_ENDED = 5; 176 private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6; 177 private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7; 178 private static final int ON_TASK_PROFILE_LOCKED = 8; 179 private static final int ON_PINNED_STACK_ANIMATION_STARTED = 9; 180 private static final int ON_ACTIVITY_UNPINNED = 10; 181 private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 11; 182 private static final int ON_TASK_CREATED = 12; 183 private static final int ON_TASK_REMOVED = 13; 184 private static final int ON_TASK_MOVED_TO_FRONT = 14; 185 private static final int ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE = 15; 186 187 188 public H(Looper looper) { 189 super(looper); 190 } 191 192 @Override 193 public void handleMessage(Message msg) { 194 synchronized (mTaskStackListeners) { 195 switch (msg.what) { 196 case ON_TASK_STACK_CHANGED: { 197 Trace.beginSection("onTaskStackChanged"); 198 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 199 mTaskStackListeners.get(i).onTaskStackChanged(); 200 } 201 Trace.endSection(); 202 break; 203 } 204 case ON_TASK_SNAPSHOT_CHANGED: { 205 Trace.beginSection("onTaskSnapshotChanged"); 206 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 207 mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1, 208 new ThumbnailData((TaskSnapshot) msg.obj)); 209 } 210 Trace.endSection(); 211 break; 212 } 213 case ON_ACTIVITY_PINNED: { 214 final PinnedActivityInfo info = (PinnedActivityInfo) msg.obj; 215 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 216 mTaskStackListeners.get(i).onActivityPinned( 217 info.mPackageName, info.mUserId, info.mTaskId, info.mStackId); 218 } 219 break; 220 } 221 case ON_ACTIVITY_UNPINNED: { 222 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 223 mTaskStackListeners.get(i).onActivityUnpinned(); 224 } 225 break; 226 } 227 case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: { 228 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 229 mTaskStackListeners.get(i).onPinnedActivityRestartAttempt( 230 msg.arg1 != 0); 231 } 232 break; 233 } 234 case ON_PINNED_STACK_ANIMATION_STARTED: { 235 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 236 mTaskStackListeners.get(i).onPinnedStackAnimationStarted(); 237 } 238 break; 239 } 240 case ON_PINNED_STACK_ANIMATION_ENDED: { 241 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 242 mTaskStackListeners.get(i).onPinnedStackAnimationEnded(); 243 } 244 break; 245 } 246 case ON_ACTIVITY_FORCED_RESIZABLE: { 247 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 248 mTaskStackListeners.get(i).onActivityForcedResizable( 249 (String) msg.obj, msg.arg1, msg.arg2); 250 } 251 break; 252 } 253 case ON_ACTIVITY_DISMISSING_DOCKED_STACK: { 254 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 255 mTaskStackListeners.get(i).onActivityDismissingDockedStack(); 256 } 257 break; 258 } 259 case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: { 260 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 261 mTaskStackListeners.get(i).onActivityLaunchOnSecondaryDisplayFailed(); 262 } 263 break; 264 } 265 case ON_TASK_PROFILE_LOCKED: { 266 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 267 mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2); 268 } 269 break; 270 } 271 case ON_TASK_CREATED: { 272 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 273 mTaskStackListeners.get(i).onTaskCreated(msg.arg1, 274 (ComponentName) msg.obj); 275 } 276 break; 277 } 278 case ON_TASK_REMOVED: { 279 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 280 mTaskStackListeners.get(i).onTaskRemoved(msg.arg1); 281 } 282 break; 283 } 284 case ON_TASK_MOVED_TO_FRONT: { 285 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 286 mTaskStackListeners.get(i).onTaskMovedToFront(msg.arg1); 287 } 288 break; 289 } 290 case ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE: { 291 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { 292 mTaskStackListeners.get(i).onActivityRequestedOrientationChanged( 293 msg.arg1, msg.arg2); 294 } 295 break; 296 } 297 } 298 } 299 } 300 } 301 302 private static class PinnedActivityInfo { 303 final String mPackageName; 304 final int mUserId; 305 final int mTaskId; 306 final int mStackId; 307 308 PinnedActivityInfo(String packageName, int userId, int taskId, int stackId) { 309 mPackageName = packageName; 310 mUserId = userId; 311 mTaskId = taskId; 312 mStackId = stackId; 313 } 314 } 315 } 316