blob: b140da501c38a8bcfbce560993e9794b17461ba5 [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;
Mark Renouf0d4bc922019-02-08 17:01:58 -050038import android.platform.test.annotations.Presubmit;
Jorim Jaggi7b614372016-09-28 15:17:50 +020039import android.support.test.uiautomator.UiDevice;
Yorke Leebd54c2a2016-10-25 13:49:23 -070040import android.text.TextUtils;
Brett Chabota26eda92018-07-23 13:08:30 -070041
Mark Renouf0d4bc922019-02-08 17:01:58 -050042import androidx.test.filters.FlakyTest;
Brett Chabota26eda92018-07-23 13:08:30 -070043import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070044
Jorim Jaggi7b614372016-09-28 15:17:50 +020045import com.android.internal.annotations.GuardedBy;
Brett Chabota26eda92018-07-23 13:08:30 -070046
Yorke Leebd54c2a2016-10-25 13:49:23 -070047import org.junit.After;
Jorim Jaggi7b614372016-09-28 15:17:50 +020048import org.junit.Before;
49import org.junit.Test;
Jorim Jaggi7b614372016-09-28 15:17:50 +020050
Brett Chabota26eda92018-07-23 13:08:30 -070051import java.util.concurrent.CountDownLatch;
52import java.util.concurrent.TimeUnit;
53
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090054/**
55 * Build/Install/Run:
56 * atest WmTests:TaskStackChangedListenerTest
57 */
Jorim Jaggi7b614372016-09-28 15:17:50 +020058@MediumTest
Yorke Leebd54c2a2016-10-25 13:49:23 -070059public class TaskStackChangedListenerTest {
Jorim Jaggi7b614372016-09-28 15:17:50 +020060
61 private IActivityManager mService;
Yorke Leebd54c2a2016-10-25 13:49:23 -070062 private ITaskStackListener mTaskStackListener;
Jorim Jaggi7b614372016-09-28 15:17:50 +020063
64 private static final Object sLock = new Object();
65 @GuardedBy("sLock")
66 private static boolean sTaskStackChangedCalled;
67 private static boolean sActivityBResumed;
68
69 @Before
70 public void setUp() throws Exception {
Sudheer Shankadc589ac2016-11-10 15:30:17 -080071 mService = ActivityManager.getService();
Yorke Leebd54c2a2016-10-25 13:49:23 -070072 }
73
74 @After
75 public void tearDown() throws Exception {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070076 ActivityTaskManager.getService().unregisterTaskStackListener(mTaskStackListener);
Yorke Leebd54c2a2016-10-25 13:49:23 -070077 mTaskStackListener = null;
Jorim Jaggi7b614372016-09-28 15:17:50 +020078 }
79
80 @Test
Mark Renouf0d4bc922019-02-08 17:01:58 -050081 @Presubmit
Jorim Jaggi7b614372016-09-28 15:17:50 +020082 public void testTaskStackChanged_afterFinish() throws Exception {
Yorke Leebd54c2a2016-10-25 13:49:23 -070083 registerTaskStackChangedListener(new TaskStackListener() {
84 @Override
85 public void onTaskStackChanged() throws RemoteException {
86 synchronized (sLock) {
87 sTaskStackChangedCalled = true;
88 }
89 }
90 });
91
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090092 Context context = getInstrumentation().getContext();
Mark Renouf0d4bc922019-02-08 17:01:58 -050093 context.startActivity(
94 new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
Jorim Jaggi7b614372016-09-28 15:17:50 +020095 UiDevice.getInstance(getInstrumentation()).waitForIdle();
96 synchronized (sLock) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090097 assertTrue(sTaskStackChangedCalled);
Jorim Jaggi7b614372016-09-28 15:17:50 +020098 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090099 assertTrue(sActivityBResumed);
Jorim Jaggi7b614372016-09-28 15:17:50 +0200100 }
101
Yorke Leebd54c2a2016-10-25 13:49:23 -0700102 @Test
103 public void testTaskDescriptionChanged() throws Exception {
104 final Object[] params = new Object[2];
105 final CountDownLatch latch = new CountDownLatch(1);
106 registerTaskStackChangedListener(new TaskStackListener() {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900107 int mTaskId = -1;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700108
109 @Override
110 public void onTaskCreated(int taskId, ComponentName componentName)
111 throws RemoteException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900112 mTaskId = taskId;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700113 }
114 @Override
115 public void onTaskDescriptionChanged(int taskId, TaskDescription td)
116 throws RemoteException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900117 if (mTaskId == taskId && !TextUtils.isEmpty(td.getLabel())) {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700118 params[0] = taskId;
119 params[1] = td;
120 latch.countDown();
121 }
122 }
123 });
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900124
125 int taskId;
126 synchronized (sLock) {
127 taskId = startTestActivity(ActivityTaskDescriptionChange.class).getTaskId();
128 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700129 waitForCallback(latch);
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900130 assertEquals(taskId, params[0]);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700131 assertEquals("Test Label", ((TaskDescription) params[1]).getLabel());
132 }
133
134 @Test
135 public void testActivityRequestedOrientationChanged() throws Exception {
136 final int[] params = new int[2];
137 final CountDownLatch latch = new CountDownLatch(1);
138 registerTaskStackChangedListener(new TaskStackListener() {
139 @Override
140 public void onActivityRequestedOrientationChanged(int taskId,
141 int requestedOrientation) {
142 params[0] = taskId;
143 params[1] = requestedOrientation;
144 latch.countDown();
145 }
146 });
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900147 int taskId;
148 synchronized (sLock) {
149 taskId = startTestActivity(ActivityRequestedOrientationChange.class).getTaskId();
150 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700151 waitForCallback(latch);
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900152 assertEquals(taskId, params[0]);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700153 assertEquals(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, params[1]);
154 }
155
Yorke Leebd54c2a2016-10-25 13:49:23 -0700156 /**
157 * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
158 */
Kazuki Takise9a0be722018-08-08 14:44:15 +0900159 @Test
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900160 @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
Yorke Leebd54c2a2016-10-25 13:49:23 -0700161 public void testTaskChangeCallBacks() throws Exception {
162 final Object[] params = new Object[2];
163 final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
164 final CountDownLatch taskMovedToFrontLatch = new CountDownLatch(1);
165 final CountDownLatch taskRemovedLatch = new CountDownLatch(1);
166 final CountDownLatch taskRemovalStartedLatch = new CountDownLatch(1);
167 final CountDownLatch onDetachedFromWindowLatch = new CountDownLatch(1);
168 registerTaskStackChangedListener(new TaskStackListener() {
169 @Override
170 public void onTaskCreated(int taskId, ComponentName componentName)
171 throws RemoteException {
172 params[0] = taskId;
173 params[1] = componentName;
174 taskCreatedLaunchLatch.countDown();
175 }
176
177 @Override
178 public void onTaskMovedToFront(int taskId) throws RemoteException {
179 params[0] = taskId;
180 taskMovedToFrontLatch.countDown();
181 }
182
183 @Override
184 public void onTaskRemovalStarted(int taskId) {
185 params[0] = taskId;
186 taskRemovalStartedLatch.countDown();
187 }
188
189 @Override
190 public void onTaskRemoved(int taskId) throws RemoteException {
191 params[0] = taskId;
192 taskRemovedLatch.countDown();
193 }
194 });
195
196 final ActivityTaskChangeCallbacks activity =
197 (ActivityTaskChangeCallbacks) startTestActivity(ActivityTaskChangeCallbacks.class);
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700198 activity.setDetachedFromWindowLatch(onDetachedFromWindowLatch);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700199 final int id = activity.getTaskId();
200
201 // Test for onTaskCreated.
202 waitForCallback(taskCreatedLaunchLatch);
203 assertEquals(id, params[0]);
204 ComponentName componentName = (ComponentName) params[1];
205 assertEquals(ActivityTaskChangeCallbacks.class.getName(), componentName.getClassName());
206
207 // Test for onTaskMovedToFront.
208 assertEquals(1, taskMovedToFrontLatch.getCount());
209 mService.moveTaskToFront(id, 0, null);
210 waitForCallback(taskMovedToFrontLatch);
211 assertEquals(activity.getTaskId(), params[0]);
212
213 // Test for onTaskRemovalStarted.
214 assertEquals(1, taskRemovalStartedLatch.getCount());
Yunfan Chenc1f3e372019-03-07 10:08:08 +0900215 assertEquals(1, taskRemovedLatch.getCount());
Yorke Leebd54c2a2016-10-25 13:49:23 -0700216 activity.finishAndRemoveTask();
217 waitForCallback(taskRemovalStartedLatch);
218 // onTaskRemovalStarted happens before the activity's window is removed.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900219 assertFalse(activity.mOnDetachedFromWindowCalled);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700220 assertEquals(id, params[0]);
221
222 // Test for onTaskRemoved.
Yorke Leebd54c2a2016-10-25 13:49:23 -0700223 waitForCallback(taskRemovedLatch);
224 assertEquals(id, params[0]);
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700225 waitForCallback(onDetachedFromWindowLatch);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900226 assertTrue(activity.mOnDetachedFromWindowCalled);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700227 }
228
229 /**
230 * Starts the provided activity and returns the started instance.
231 */
Kazuki Takise9a0be722018-08-08 14:44:15 +0900232 private TestActivity startTestActivity(Class<?> activityClass) throws InterruptedException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900233 final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false);
234 getInstrumentation().addMonitor(monitor);
235 final Context context = getInstrumentation().getContext();
Mark Renouf0d4bc922019-02-08 17:01:58 -0500236 context.startActivity(
237 new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900238 final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700239 if (activity == null) {
240 throw new RuntimeException("Timed out waiting for Activity");
Jorim Jaggi7b614372016-09-28 15:17:50 +0200241 }
Kazuki Takise9a0be722018-08-08 14:44:15 +0900242 activity.waitForResumeStateChange(true);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700243 return activity;
Jorim Jaggi7b614372016-09-28 15:17:50 +0200244 }
245
Yorke Leebd54c2a2016-10-25 13:49:23 -0700246 private void registerTaskStackChangedListener(ITaskStackListener listener) throws Exception {
247 mTaskStackListener = listener;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700248 ActivityTaskManager.getService().registerTaskStackListener(listener);
Jorim Jaggi7b614372016-09-28 15:17:50 +0200249 }
250
Yorke Leebd54c2a2016-10-25 13:49:23 -0700251 private void waitForCallback(CountDownLatch latch) {
252 try {
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900253 final boolean result = latch.await(4, TimeUnit.SECONDS);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700254 if (!result) {
255 throw new RuntimeException("Timed out waiting for task stack change notification");
256 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900257 } catch (InterruptedException e) {
258 }
Jorim Jaggi7b614372016-09-28 15:17:50 +0200259 }
260
Kazuki Takise9a0be722018-08-08 14:44:15 +0900261 public static class TestActivity extends Activity {
262 boolean mIsResumed = false;
263
264 @Override
265 protected void onPostResume() {
266 super.onPostResume();
267 synchronized (this) {
268 mIsResumed = true;
269 notifyAll();
270 }
271 }
272
273 @Override
274 protected void onPause() {
275 super.onPause();
276 synchronized (this) {
277 mIsResumed = false;
278 notifyAll();
279 }
280 }
281
282 /**
283 * If isResumed is {@code true}, sleep the thread until the activity is resumed.
284 * if {@code false}, sleep the thread until the activity is paused.
285 */
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900286 @SuppressWarnings("WaitNotInLoop")
Kazuki Takise9a0be722018-08-08 14:44:15 +0900287 public void waitForResumeStateChange(boolean isResumed) throws InterruptedException {
288 synchronized (this) {
289 if (mIsResumed == isResumed) {
290 return;
291 }
292 wait(5000);
293 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900294 assertEquals("The activity resume state change timed out", isResumed, mIsResumed);
Kazuki Takise9a0be722018-08-08 14:44:15 +0900295 }
296 }
297
298 public static class ActivityA extends TestActivity {
Jorim Jaggi7b614372016-09-28 15:17:50 +0200299
300 private boolean mActivityBLaunched = false;
301
302 @Override
303 protected void onPostResume() {
304 super.onPostResume();
305 if (mActivityBLaunched) {
306 return;
307 }
308 mActivityBLaunched = true;
309 finish();
310 startActivity(new Intent(this, ActivityB.class));
311 }
312 }
313
Kazuki Takise9a0be722018-08-08 14:44:15 +0900314 public static class ActivityB extends TestActivity {
Jorim Jaggi7b614372016-09-28 15:17:50 +0200315
316 @Override
317 protected void onPostResume() {
318 super.onPostResume();
319 synchronized (sLock) {
320 sTaskStackChangedCalled = false;
321 }
322 sActivityBResumed = true;
323 finish();
324 }
325 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700326
Kazuki Takise9a0be722018-08-08 14:44:15 +0900327 public static class ActivityRequestedOrientationChange extends TestActivity {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700328 @Override
329 protected void onPostResume() {
330 super.onPostResume();
331 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900332 synchronized (sLock) {
333 // Hold the lock to ensure no one is trying to access fields of this Activity in
334 // this test.
335 finish();
336 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700337 }
338 }
339
Kazuki Takise9a0be722018-08-08 14:44:15 +0900340 public static class ActivityTaskDescriptionChange extends TestActivity {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700341 @Override
342 protected void onPostResume() {
343 super.onPostResume();
344 setTaskDescription(new TaskDescription("Test Label"));
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900345 synchronized (sLock) {
346 // Hold the lock to ensure no one is trying to access fields of this Activity in
347 // this test.
348 finish();
349 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700350 }
351 }
352
Kazuki Takise9a0be722018-08-08 14:44:15 +0900353 public static class ActivityTaskChangeCallbacks extends TestActivity {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900354 public boolean mOnDetachedFromWindowCalled = false;
355 private CountDownLatch mOnDetachedFromWindowCountDownLatch;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700356
357 @Override
358 public void onDetachedFromWindow() {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900359 mOnDetachedFromWindowCalled = true;
360 mOnDetachedFromWindowCountDownLatch.countDown();
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700361 }
362
363 void setDetachedFromWindowLatch(CountDownLatch countDownLatch) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900364 mOnDetachedFromWindowCountDownLatch = countDownLatch;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700365 }
366 }
Jorim Jaggi7b614372016-09-28 15:17:50 +0200367}