blob: fd248c6c807ad72a1e974ae0bf14005ce7e6ca8e [file] [log] [blame]
Yorke Leebd54c2a2016-10-25 13:49:23 -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 */
16
17package com.android.server.am;
18
19import android.app.ITaskStackListener;
20import android.app.ActivityManager.TaskDescription;
21import android.content.ComponentName;
22import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25import android.os.RemoteCallbackList;
26import android.os.RemoteException;
27
28class TaskChangeNotificationController {
29 static final int LOG_STACK_STATE_MSG = 1;
30 static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 2;
31 static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 3;
32 static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
33 static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 5;
34 static final int NOTIFY_FORCED_RESIZABLE_MSG = 6;
35 static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 7;
36 static final int NOTIFY_TASK_ADDED_LISTENERS_MSG = 8;
37 static final int NOTIFY_TASK_REMOVED_LISTENERS_MSG = 9;
38 static final int NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG = 10;
39 static final int NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG = 11;
40 static final int NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS = 12;
41 static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
42
43 // Delay in notifying task stack change listeners (in millis)
44 static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
45
46 private final ActivityManagerService mService;
47 private final ActivityStackSupervisor mStackSupervisor;
48 private final Handler mHandler;
49
50 /** Task stack change listeners. */
51 private final RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
52 new RemoteCallbackList<ITaskStackListener>();
53
54 @FunctionalInterface
55 public interface ConsumerWithRemoteException<T> {
56 void accept(T t) throws RemoteException;
57 }
58
59 private class MainHandler extends Handler {
60 public MainHandler(Looper looper) {
61 super(looper);
62 }
63
64 @Override
65 public void handleMessage(Message msg) {
66 switch (msg.what) {
67 case LOG_STACK_STATE_MSG: {
68 synchronized (mService) {
69 mStackSupervisor.logStackState();
70 }
71 break;
72 }
73 case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG:
74 forAllListeners((listener) -> listener.onTaskStackChanged());
75 break;
76 case NOTIFY_TASK_ADDED_LISTENERS_MSG:
77 forAllListeners((listener) -> listener.onTaskCreated(msg.arg1,
78 (ComponentName) msg.obj));
79 break;
80 case NOTIFY_TASK_REMOVED_LISTENERS_MSG:
81 forAllListeners((listener) -> listener.onTaskRemoved(msg.arg1));
82 break;
83 case NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG:
84 forAllListeners((listener) -> listener.onTaskMovedToFront(msg.arg1));
85 break;
86 case NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG:
87 forAllListeners((listener) -> listener.onTaskDescriptionChanged(msg.arg1,
88 (TaskDescription) msg.obj));
89 break;
90 case NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS:
91 forAllListeners((listener) -> listener.onActivityRequestedOrientationChanged(
92 msg.arg1, msg.arg2));
Yorke Lee64fd1ce2017-01-05 17:15:20 -080093 break;
Yorke Leebd54c2a2016-10-25 13:49:23 -070094 case NOTIFY_TASK_REMOVAL_STARTED_LISTENERS:
95 forAllListeners((listener) -> listener.onTaskRemovalStarted(msg.arg1));
96 break;
97 case NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG:
98 forAllListeners((listener) -> listener.onActivityPinned());
99 break;
100 case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
101 forAllListeners((listener) -> listener.onPinnedActivityRestartAttempt());
102 break;
103 case NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG:
104 forAllListeners((listener) -> listener.onPinnedStackAnimationEnded());
105 break;
106 case NOTIFY_FORCED_RESIZABLE_MSG:
107 forAllListeners((listener) -> listener.onActivityForcedResizable(
108 (String) msg.obj, msg.arg1));
109 break;
110 case NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG:
111 forAllListeners((listener) -> listener.onActivityDismissingDockedStack());
112 break;
113 }
114 }
115 }
116
117 public TaskChangeNotificationController(ActivityManagerService service,
118 ActivityStackSupervisor stackSupervisor, Handler handler) {
119 mService = service;
120 mStackSupervisor = stackSupervisor;
121 mHandler = new MainHandler(handler.getLooper());
122 }
123
124 public void registerTaskStackListener(ITaskStackListener listener) {
125 synchronized (mService) {
126 if (listener != null) {
127 mTaskStackListeners.register(listener);
128 }
129 }
130 }
131
132 public void unregisterTaskStackListener(ITaskStackListener listener) {
133 synchronized (mService) {
134 if (listener != null) {
135 mTaskStackListeners.unregister(listener);
136 }
137 }
138 }
139
140 void forAllListeners(ConsumerWithRemoteException<ITaskStackListener> callback) {
141 synchronized (mService) {
142 for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
143 try {
144 // Make a one-way callback to the listener
145 callback.accept(mTaskStackListeners.getBroadcastItem(i));
146 } catch (RemoteException e) {
147 // Handled by the RemoteCallbackList.
148 }
149 }
150 mTaskStackListeners.finishBroadcast();
151 }
152 }
153
154 /** Notifies all listeners when the task stack has changed. */
155 void notifyTaskStackChanged() {
156 mHandler.sendEmptyMessage(LOG_STACK_STATE_MSG);
157 mHandler.removeMessages(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
158 Message msg = mHandler.obtainMessage(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
159 // Only the main task stack change notification requires a delay.
160 mHandler.sendMessageDelayed(msg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
161 }
162
163 /** Notifies all listeners when an Activity is pinned. */
164 void notifyActivityPinned() {
165 mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
166 mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG).sendToTarget();
167 }
168
169 /**
170 * Notifies all listeners when an attempt was made to start an an activity that is already
171 * running in the pinned stack and the activity was not actually started, but the task is
172 * either brought to the front or a new Intent is delivered to it.
173 */
174 void notifyPinnedActivityRestartAttempt() {
175 mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
176 mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG).sendToTarget();
177 }
178
179 /** Notifies all listeners when the pinned stack animation ends. */
180 void notifyPinnedStackAnimationEnded() {
181 mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG);
182 mHandler.obtainMessage(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG)
183 .sendToTarget();
184 }
185
186 void notifyActivityDismissingDockedStack() {
187 mHandler.removeMessages(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
188 mHandler.obtainMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG).sendToTarget();
189 }
190
191 void notifyActivityForcedResizable(int taskId, String packageName) {
192 mHandler.removeMessages(NOTIFY_FORCED_RESIZABLE_MSG);
193 mHandler.obtainMessage(NOTIFY_FORCED_RESIZABLE_MSG, taskId, 0 /* unused */, packageName)
194 .sendToTarget();
195 }
196
197 void notifyTaskCreated(int taskId, ComponentName componentName) {
198 mHandler.obtainMessage(NOTIFY_TASK_ADDED_LISTENERS_MSG, taskId, 0 /* unused */,
199 componentName).sendToTarget();
200 }
201
202 void notifyTaskRemoved(int taskId) {
203 mHandler.obtainMessage(NOTIFY_TASK_REMOVED_LISTENERS_MSG, taskId, 0 /* unused */)
204 .sendToTarget();
205 }
206
207 void notifyTaskMovedToFront(int taskId) {
208 mHandler.obtainMessage(NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG, taskId, 0 /* unused */)
209 .sendToTarget();
210 }
211
212 void notifyTaskDescriptionChanged(int taskId, TaskDescription taskDescription) {
213 mHandler.obtainMessage(NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG, taskId,
214 0 /* unused */, taskDescription).sendToTarget();
215 }
216
217 void notifyActivityRequestedOrientationChanged(int taskId, int orientation) {
218 mHandler.obtainMessage(NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS, taskId,
219 orientation).sendToTarget();
220 }
221
222 /**
223 * Notify listeners that the task is about to be finished before its surfaces are removed from
224 * the window manager. This allows interested parties to perform relevant animations before
225 * the window disappears.
226 */
227 void notifyTaskRemovalStarted(int taskId) {
228 mHandler.obtainMessage(NOTIFY_TASK_REMOVAL_STARTED_LISTENERS, taskId, 0 /* unused */)
229 .sendToTarget();
230 }
231}