blob: 4a734e5256f631cc9a8d28cd3140dc8908fa53b7 [file] [log] [blame]
Jorim Jaggi7b614372016-09-28 15:17:50 +02001/*
Wale Ogunwale59507092018-10-29 09:00:30 -07002 * Copyright (C) 2018 The Android Open Source Project
Jorim Jaggi7b614372016-09-28 15:17:50 +02003 *
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
Wale Ogunwale59507092018-10-29 09:00:30 -070014 * limitations under the License
Jorim Jaggi7b614372016-09-28 15:17:50 +020015 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Jorim Jaggi7b614372016-09-28 15:17:50 +020018
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090019import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
Brett Chabota26eda92018-07-23 13:08:30 -070020
Yorke Leebd54c2a2016-10-25 13:49:23 -070021import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertFalse;
23import static org.junit.Assert.assertTrue;
Jorim Jaggi7b614372016-09-28 15:17:50 +020024
25import android.app.Activity;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080026import android.app.ActivityManager;
Yorke Leebd54c2a2016-10-25 13:49:23 -070027import android.app.ActivityManager.TaskDescription;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070028import android.app.ActivityTaskManager;
Jorim Jaggi7b614372016-09-28 15:17:50 +020029import android.app.IActivityManager;
30import android.app.ITaskStackListener;
Yorke Leebd54c2a2016-10-25 13:49:23 -070031import android.app.Instrumentation.ActivityMonitor;
32import android.app.TaskStackListener;
33import android.content.ComponentName;
Jorim Jaggi7b614372016-09-28 15:17:50 +020034import android.content.Context;
35import android.content.Intent;
Yorke Leebd54c2a2016-10-25 13:49:23 -070036import android.content.pm.ActivityInfo;
Jorim Jaggi7b614372016-09-28 15:17:50 +020037import android.os.RemoteException;
Jorim Jaggi7b614372016-09-28 15:17:50 +020038import android.support.test.uiautomator.UiDevice;
Yorke Leebd54c2a2016-10-25 13:49:23 -070039import android.text.TextUtils;
Brett Chabota26eda92018-07-23 13:08:30 -070040
Brett Chabota26eda92018-07-23 13:08:30 -070041import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070042
Jorim Jaggi7b614372016-09-28 15:17:50 +020043import com.android.internal.annotations.GuardedBy;
Brett Chabota26eda92018-07-23 13:08:30 -070044
Yorke Leebd54c2a2016-10-25 13:49:23 -070045import org.junit.After;
Jorim Jaggi7b614372016-09-28 15:17:50 +020046import org.junit.Before;
47import org.junit.Test;
Jorim Jaggi7b614372016-09-28 15:17:50 +020048
Brett Chabota26eda92018-07-23 13:08:30 -070049import java.util.concurrent.CountDownLatch;
50import java.util.concurrent.TimeUnit;
51
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090052/**
53 * Build/Install/Run:
54 * atest WmTests:TaskStackChangedListenerTest
55 */
Jorim Jaggi7b614372016-09-28 15:17:50 +020056@MediumTest
Yorke Leebd54c2a2016-10-25 13:49:23 -070057public class TaskStackChangedListenerTest {
Jorim Jaggi7b614372016-09-28 15:17:50 +020058
59 private IActivityManager mService;
Yorke Leebd54c2a2016-10-25 13:49:23 -070060 private ITaskStackListener mTaskStackListener;
Jorim Jaggi7b614372016-09-28 15:17:50 +020061
62 private static final Object sLock = new Object();
63 @GuardedBy("sLock")
64 private static boolean sTaskStackChangedCalled;
65 private static boolean sActivityBResumed;
66
67 @Before
68 public void setUp() throws Exception {
Sudheer Shankadc589ac2016-11-10 15:30:17 -080069 mService = ActivityManager.getService();
Yorke Leebd54c2a2016-10-25 13:49:23 -070070 }
71
72 @After
73 public void tearDown() throws Exception {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070074 ActivityTaskManager.getService().unregisterTaskStackListener(mTaskStackListener);
Yorke Leebd54c2a2016-10-25 13:49:23 -070075 mTaskStackListener = null;
Jorim Jaggi7b614372016-09-28 15:17:50 +020076 }
77
78 @Test
79 public void testTaskStackChanged_afterFinish() throws Exception {
Yorke Leebd54c2a2016-10-25 13:49:23 -070080 registerTaskStackChangedListener(new TaskStackListener() {
81 @Override
82 public void onTaskStackChanged() throws RemoteException {
83 synchronized (sLock) {
84 sTaskStackChangedCalled = true;
85 }
86 }
87 });
88
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090089 Context context = getInstrumentation().getContext();
90 context.startActivity(new Intent(context, ActivityA.class));
Jorim Jaggi7b614372016-09-28 15:17:50 +020091 UiDevice.getInstance(getInstrumentation()).waitForIdle();
92 synchronized (sLock) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090093 assertTrue(sTaskStackChangedCalled);
Jorim Jaggi7b614372016-09-28 15:17:50 +020094 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090095 assertTrue(sActivityBResumed);
Jorim Jaggi7b614372016-09-28 15:17:50 +020096 }
97
Yorke Leebd54c2a2016-10-25 13:49:23 -070098 @Test
99 public void testTaskDescriptionChanged() throws Exception {
100 final Object[] params = new Object[2];
101 final CountDownLatch latch = new CountDownLatch(1);
102 registerTaskStackChangedListener(new TaskStackListener() {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900103 int mTaskId = -1;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700104
105 @Override
106 public void onTaskCreated(int taskId, ComponentName componentName)
107 throws RemoteException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900108 mTaskId = taskId;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700109 }
110 @Override
111 public void onTaskDescriptionChanged(int taskId, TaskDescription td)
112 throws RemoteException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900113 if (mTaskId == taskId && !TextUtils.isEmpty(td.getLabel())) {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700114 params[0] = taskId;
115 params[1] = td;
116 latch.countDown();
117 }
118 }
119 });
120 final Activity activity = startTestActivity(ActivityTaskDescriptionChange.class);
121 waitForCallback(latch);
122 assertEquals(activity.getTaskId(), params[0]);
123 assertEquals("Test Label", ((TaskDescription) params[1]).getLabel());
124 }
125
126 @Test
127 public void testActivityRequestedOrientationChanged() throws Exception {
128 final int[] params = new int[2];
129 final CountDownLatch latch = new CountDownLatch(1);
130 registerTaskStackChangedListener(new TaskStackListener() {
131 @Override
132 public void onActivityRequestedOrientationChanged(int taskId,
133 int requestedOrientation) {
134 params[0] = taskId;
135 params[1] = requestedOrientation;
136 latch.countDown();
137 }
138 });
139 final Activity activity = startTestActivity(ActivityRequestedOrientationChange.class);
140 waitForCallback(latch);
141 assertEquals(activity.getTaskId(), params[0]);
142 assertEquals(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, params[1]);
143 }
144
Yorke Leebd54c2a2016-10-25 13:49:23 -0700145 /**
146 * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
147 */
Kazuki Takise9a0be722018-08-08 14:44:15 +0900148 @Test
Yorke Leebd54c2a2016-10-25 13:49:23 -0700149 public void testTaskChangeCallBacks() throws Exception {
150 final Object[] params = new Object[2];
151 final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
152 final CountDownLatch taskMovedToFrontLatch = new CountDownLatch(1);
153 final CountDownLatch taskRemovedLatch = new CountDownLatch(1);
154 final CountDownLatch taskRemovalStartedLatch = new CountDownLatch(1);
155 final CountDownLatch onDetachedFromWindowLatch = new CountDownLatch(1);
156 registerTaskStackChangedListener(new TaskStackListener() {
157 @Override
158 public void onTaskCreated(int taskId, ComponentName componentName)
159 throws RemoteException {
160 params[0] = taskId;
161 params[1] = componentName;
162 taskCreatedLaunchLatch.countDown();
163 }
164
165 @Override
166 public void onTaskMovedToFront(int taskId) throws RemoteException {
167 params[0] = taskId;
168 taskMovedToFrontLatch.countDown();
169 }
170
171 @Override
172 public void onTaskRemovalStarted(int taskId) {
173 params[0] = taskId;
174 taskRemovalStartedLatch.countDown();
175 }
176
177 @Override
178 public void onTaskRemoved(int taskId) throws RemoteException {
179 params[0] = taskId;
180 taskRemovedLatch.countDown();
181 }
182 });
183
184 final ActivityTaskChangeCallbacks activity =
185 (ActivityTaskChangeCallbacks) startTestActivity(ActivityTaskChangeCallbacks.class);
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700186 activity.setDetachedFromWindowLatch(onDetachedFromWindowLatch);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700187 final int id = activity.getTaskId();
188
189 // Test for onTaskCreated.
190 waitForCallback(taskCreatedLaunchLatch);
191 assertEquals(id, params[0]);
192 ComponentName componentName = (ComponentName) params[1];
193 assertEquals(ActivityTaskChangeCallbacks.class.getName(), componentName.getClassName());
194
195 // Test for onTaskMovedToFront.
196 assertEquals(1, taskMovedToFrontLatch.getCount());
197 mService.moveTaskToFront(id, 0, null);
198 waitForCallback(taskMovedToFrontLatch);
199 assertEquals(activity.getTaskId(), params[0]);
200
201 // Test for onTaskRemovalStarted.
202 assertEquals(1, taskRemovalStartedLatch.getCount());
203 activity.finishAndRemoveTask();
204 waitForCallback(taskRemovalStartedLatch);
205 // onTaskRemovalStarted happens before the activity's window is removed.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900206 assertFalse(activity.mOnDetachedFromWindowCalled);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700207 assertEquals(id, params[0]);
208
209 // Test for onTaskRemoved.
210 assertEquals(1, taskRemovedLatch.getCount());
211 waitForCallback(taskRemovedLatch);
212 assertEquals(id, params[0]);
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700213 waitForCallback(onDetachedFromWindowLatch);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900214 assertTrue(activity.mOnDetachedFromWindowCalled);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700215 }
216
217 /**
218 * Starts the provided activity and returns the started instance.
219 */
Kazuki Takise9a0be722018-08-08 14:44:15 +0900220 private TestActivity startTestActivity(Class<?> activityClass) throws InterruptedException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900221 final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false);
222 getInstrumentation().addMonitor(monitor);
223 final Context context = getInstrumentation().getContext();
Yorke Leebd54c2a2016-10-25 13:49:23 -0700224 context.startActivity(new Intent(context, activityClass));
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900225 final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700226 if (activity == null) {
227 throw new RuntimeException("Timed out waiting for Activity");
Jorim Jaggi7b614372016-09-28 15:17:50 +0200228 }
Kazuki Takise9a0be722018-08-08 14:44:15 +0900229 activity.waitForResumeStateChange(true);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700230 return activity;
Jorim Jaggi7b614372016-09-28 15:17:50 +0200231 }
232
Yorke Leebd54c2a2016-10-25 13:49:23 -0700233 private void registerTaskStackChangedListener(ITaskStackListener listener) throws Exception {
234 mTaskStackListener = listener;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700235 ActivityTaskManager.getService().registerTaskStackListener(listener);
Jorim Jaggi7b614372016-09-28 15:17:50 +0200236 }
237
Yorke Leebd54c2a2016-10-25 13:49:23 -0700238 private void waitForCallback(CountDownLatch latch) {
239 try {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900240 final boolean result = latch.await(2, TimeUnit.SECONDS);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700241 if (!result) {
242 throw new RuntimeException("Timed out waiting for task stack change notification");
243 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900244 } catch (InterruptedException e) {
245 }
Jorim Jaggi7b614372016-09-28 15:17:50 +0200246 }
247
Kazuki Takise9a0be722018-08-08 14:44:15 +0900248 public static class TestActivity extends Activity {
249 boolean mIsResumed = false;
250
251 @Override
252 protected void onPostResume() {
253 super.onPostResume();
254 synchronized (this) {
255 mIsResumed = true;
256 notifyAll();
257 }
258 }
259
260 @Override
261 protected void onPause() {
262 super.onPause();
263 synchronized (this) {
264 mIsResumed = false;
265 notifyAll();
266 }
267 }
268
269 /**
270 * If isResumed is {@code true}, sleep the thread until the activity is resumed.
271 * if {@code false}, sleep the thread until the activity is paused.
272 */
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900273 @SuppressWarnings("WaitNotInLoop")
Kazuki Takise9a0be722018-08-08 14:44:15 +0900274 public void waitForResumeStateChange(boolean isResumed) throws InterruptedException {
275 synchronized (this) {
276 if (mIsResumed == isResumed) {
277 return;
278 }
279 wait(5000);
280 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900281 assertEquals("The activity resume state change timed out", isResumed, mIsResumed);
Kazuki Takise9a0be722018-08-08 14:44:15 +0900282 }
283 }
284
285 public static class ActivityA extends TestActivity {
Jorim Jaggi7b614372016-09-28 15:17:50 +0200286
287 private boolean mActivityBLaunched = false;
288
289 @Override
290 protected void onPostResume() {
291 super.onPostResume();
292 if (mActivityBLaunched) {
293 return;
294 }
295 mActivityBLaunched = true;
296 finish();
297 startActivity(new Intent(this, ActivityB.class));
298 }
299 }
300
Kazuki Takise9a0be722018-08-08 14:44:15 +0900301 public static class ActivityB extends TestActivity {
Jorim Jaggi7b614372016-09-28 15:17:50 +0200302
303 @Override
304 protected void onPostResume() {
305 super.onPostResume();
306 synchronized (sLock) {
307 sTaskStackChangedCalled = false;
308 }
309 sActivityBResumed = true;
310 finish();
311 }
312 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700313
Kazuki Takise9a0be722018-08-08 14:44:15 +0900314 public static class ActivityRequestedOrientationChange extends TestActivity {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700315 @Override
316 protected void onPostResume() {
317 super.onPostResume();
318 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
319 finish();
320 }
321 }
322
Kazuki Takise9a0be722018-08-08 14:44:15 +0900323 public static class ActivityTaskDescriptionChange extends TestActivity {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700324 @Override
325 protected void onPostResume() {
326 super.onPostResume();
327 setTaskDescription(new TaskDescription("Test Label"));
328 finish();
329 }
330 }
331
Kazuki Takise9a0be722018-08-08 14:44:15 +0900332 public static class ActivityTaskChangeCallbacks extends TestActivity {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900333 public boolean mOnDetachedFromWindowCalled = false;
334 private CountDownLatch mOnDetachedFromWindowCountDownLatch;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700335
336 @Override
337 public void onDetachedFromWindow() {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900338 mOnDetachedFromWindowCalled = true;
339 mOnDetachedFromWindowCountDownLatch.countDown();
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700340 }
341
342 void setDetachedFromWindowLatch(CountDownLatch countDownLatch) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900343 mOnDetachedFromWindowCountDownLatch = countDownLatch;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700344 }
345 }
Jorim Jaggi7b614372016-09-28 15:17:50 +0200346}