blob: d8a01b9eb9b49fccfe5da70c9f1b155a2f072967 [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
Yunfan Chen6a938aa2019-03-13 13:59:07 -0700103 @Presubmit
Yorke Leebd54c2a2016-10-25 13:49:23 -0700104 public void testTaskDescriptionChanged() throws Exception {
105 final Object[] params = new Object[2];
106 final CountDownLatch latch = new CountDownLatch(1);
107 registerTaskStackChangedListener(new TaskStackListener() {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900108 int mTaskId = -1;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700109
110 @Override
111 public void onTaskCreated(int taskId, ComponentName componentName)
112 throws RemoteException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900113 mTaskId = taskId;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700114 }
115 @Override
116 public void onTaskDescriptionChanged(int taskId, TaskDescription td)
117 throws RemoteException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900118 if (mTaskId == taskId && !TextUtils.isEmpty(td.getLabel())) {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700119 params[0] = taskId;
120 params[1] = td;
121 latch.countDown();
122 }
123 }
124 });
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900125
126 int taskId;
127 synchronized (sLock) {
128 taskId = startTestActivity(ActivityTaskDescriptionChange.class).getTaskId();
129 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700130 waitForCallback(latch);
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900131 assertEquals(taskId, params[0]);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700132 assertEquals("Test Label", ((TaskDescription) params[1]).getLabel());
133 }
134
135 @Test
Yunfan Chen6a938aa2019-03-13 13:59:07 -0700136 @Presubmit
Yorke Leebd54c2a2016-10-25 13:49:23 -0700137 public void testActivityRequestedOrientationChanged() throws Exception {
138 final int[] params = new int[2];
139 final CountDownLatch latch = new CountDownLatch(1);
140 registerTaskStackChangedListener(new TaskStackListener() {
141 @Override
142 public void onActivityRequestedOrientationChanged(int taskId,
143 int requestedOrientation) {
144 params[0] = taskId;
145 params[1] = requestedOrientation;
146 latch.countDown();
147 }
148 });
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900149 int taskId;
150 synchronized (sLock) {
151 taskId = startTestActivity(ActivityRequestedOrientationChange.class).getTaskId();
152 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700153 waitForCallback(latch);
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900154 assertEquals(taskId, params[0]);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700155 assertEquals(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, params[1]);
156 }
157
Yorke Leebd54c2a2016-10-25 13:49:23 -0700158 /**
159 * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
160 */
Kazuki Takise9a0be722018-08-08 14:44:15 +0900161 @Test
Yorke Leebd54c2a2016-10-25 13:49:23 -0700162 public void testTaskChangeCallBacks() throws Exception {
163 final Object[] params = new Object[2];
164 final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
165 final CountDownLatch taskMovedToFrontLatch = new CountDownLatch(1);
166 final CountDownLatch taskRemovedLatch = new CountDownLatch(1);
167 final CountDownLatch taskRemovalStartedLatch = new CountDownLatch(1);
168 final CountDownLatch onDetachedFromWindowLatch = new CountDownLatch(1);
169 registerTaskStackChangedListener(new TaskStackListener() {
170 @Override
171 public void onTaskCreated(int taskId, ComponentName componentName)
172 throws RemoteException {
173 params[0] = taskId;
174 params[1] = componentName;
175 taskCreatedLaunchLatch.countDown();
176 }
177
178 @Override
179 public void onTaskMovedToFront(int taskId) throws RemoteException {
180 params[0] = taskId;
181 taskMovedToFrontLatch.countDown();
182 }
183
184 @Override
185 public void onTaskRemovalStarted(int taskId) {
186 params[0] = taskId;
187 taskRemovalStartedLatch.countDown();
188 }
189
190 @Override
191 public void onTaskRemoved(int taskId) throws RemoteException {
192 params[0] = taskId;
193 taskRemovedLatch.countDown();
194 }
195 });
196
197 final ActivityTaskChangeCallbacks activity =
198 (ActivityTaskChangeCallbacks) startTestActivity(ActivityTaskChangeCallbacks.class);
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700199 activity.setDetachedFromWindowLatch(onDetachedFromWindowLatch);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700200 final int id = activity.getTaskId();
201
202 // Test for onTaskCreated.
203 waitForCallback(taskCreatedLaunchLatch);
204 assertEquals(id, params[0]);
205 ComponentName componentName = (ComponentName) params[1];
206 assertEquals(ActivityTaskChangeCallbacks.class.getName(), componentName.getClassName());
207
208 // Test for onTaskMovedToFront.
209 assertEquals(1, taskMovedToFrontLatch.getCount());
210 mService.moveTaskToFront(id, 0, null);
211 waitForCallback(taskMovedToFrontLatch);
212 assertEquals(activity.getTaskId(), params[0]);
213
214 // Test for onTaskRemovalStarted.
215 assertEquals(1, taskRemovalStartedLatch.getCount());
Yunfan Chenc1f3e372019-03-07 10:08:08 +0900216 assertEquals(1, taskRemovedLatch.getCount());
Yorke Leebd54c2a2016-10-25 13:49:23 -0700217 activity.finishAndRemoveTask();
218 waitForCallback(taskRemovalStartedLatch);
219 // onTaskRemovalStarted happens before the activity's window is removed.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900220 assertFalse(activity.mOnDetachedFromWindowCalled);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700221 assertEquals(id, params[0]);
222
223 // Test for onTaskRemoved.
Yorke Leebd54c2a2016-10-25 13:49:23 -0700224 waitForCallback(taskRemovedLatch);
225 assertEquals(id, params[0]);
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700226 waitForCallback(onDetachedFromWindowLatch);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900227 assertTrue(activity.mOnDetachedFromWindowCalled);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700228 }
229
230 /**
231 * Starts the provided activity and returns the started instance.
232 */
Kazuki Takise9a0be722018-08-08 14:44:15 +0900233 private TestActivity startTestActivity(Class<?> activityClass) throws InterruptedException {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900234 final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false);
235 getInstrumentation().addMonitor(monitor);
236 final Context context = getInstrumentation().getContext();
Mark Renouf0d4bc922019-02-08 17:01:58 -0500237 context.startActivity(
238 new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900239 final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700240 if (activity == null) {
241 throw new RuntimeException("Timed out waiting for Activity");
Jorim Jaggi7b614372016-09-28 15:17:50 +0200242 }
Kazuki Takise9a0be722018-08-08 14:44:15 +0900243 activity.waitForResumeStateChange(true);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700244 return activity;
Jorim Jaggi7b614372016-09-28 15:17:50 +0200245 }
246
Yorke Leebd54c2a2016-10-25 13:49:23 -0700247 private void registerTaskStackChangedListener(ITaskStackListener listener) throws Exception {
248 mTaskStackListener = listener;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700249 ActivityTaskManager.getService().registerTaskStackListener(listener);
Jorim Jaggi7b614372016-09-28 15:17:50 +0200250 }
251
Yorke Leebd54c2a2016-10-25 13:49:23 -0700252 private void waitForCallback(CountDownLatch latch) {
253 try {
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900254 final boolean result = latch.await(4, TimeUnit.SECONDS);
Yorke Leebd54c2a2016-10-25 13:49:23 -0700255 if (!result) {
256 throw new RuntimeException("Timed out waiting for task stack change notification");
257 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900258 } catch (InterruptedException e) {
259 }
Jorim Jaggi7b614372016-09-28 15:17:50 +0200260 }
261
Kazuki Takise9a0be722018-08-08 14:44:15 +0900262 public static class TestActivity extends Activity {
263 boolean mIsResumed = false;
264
265 @Override
266 protected void onPostResume() {
267 super.onPostResume();
268 synchronized (this) {
269 mIsResumed = true;
270 notifyAll();
271 }
272 }
273
274 @Override
275 protected void onPause() {
276 super.onPause();
277 synchronized (this) {
278 mIsResumed = false;
279 notifyAll();
280 }
281 }
282
283 /**
284 * If isResumed is {@code true}, sleep the thread until the activity is resumed.
285 * if {@code false}, sleep the thread until the activity is paused.
286 */
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900287 @SuppressWarnings("WaitNotInLoop")
Kazuki Takise9a0be722018-08-08 14:44:15 +0900288 public void waitForResumeStateChange(boolean isResumed) throws InterruptedException {
289 synchronized (this) {
290 if (mIsResumed == isResumed) {
291 return;
292 }
293 wait(5000);
294 }
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900295 assertEquals("The activity resume state change timed out", isResumed, mIsResumed);
Kazuki Takise9a0be722018-08-08 14:44:15 +0900296 }
297 }
298
299 public static class ActivityA extends TestActivity {
Jorim Jaggi7b614372016-09-28 15:17:50 +0200300
301 private boolean mActivityBLaunched = false;
302
303 @Override
304 protected void onPostResume() {
305 super.onPostResume();
306 if (mActivityBLaunched) {
307 return;
308 }
309 mActivityBLaunched = true;
310 finish();
311 startActivity(new Intent(this, ActivityB.class));
312 }
313 }
314
Kazuki Takise9a0be722018-08-08 14:44:15 +0900315 public static class ActivityB extends TestActivity {
Jorim Jaggi7b614372016-09-28 15:17:50 +0200316
317 @Override
318 protected void onPostResume() {
319 super.onPostResume();
320 synchronized (sLock) {
321 sTaskStackChangedCalled = false;
322 }
323 sActivityBResumed = true;
324 finish();
325 }
326 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700327
Kazuki Takise9a0be722018-08-08 14:44:15 +0900328 public static class ActivityRequestedOrientationChange extends TestActivity {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700329 @Override
330 protected void onPostResume() {
331 super.onPostResume();
332 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900333 synchronized (sLock) {
334 // Hold the lock to ensure no one is trying to access fields of this Activity in
335 // this test.
336 finish();
337 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700338 }
339 }
340
Kazuki Takise9a0be722018-08-08 14:44:15 +0900341 public static class ActivityTaskDescriptionChange extends TestActivity {
Yorke Leebd54c2a2016-10-25 13:49:23 -0700342 @Override
343 protected void onPostResume() {
344 super.onPostResume();
345 setTaskDescription(new TaskDescription("Test Label"));
Yunfan Chen968cc7f2019-02-15 20:14:14 +0900346 synchronized (sLock) {
347 // Hold the lock to ensure no one is trying to access fields of this Activity in
348 // this test.
349 finish();
350 }
Yorke Leebd54c2a2016-10-25 13:49:23 -0700351 }
352 }
353
Kazuki Takise9a0be722018-08-08 14:44:15 +0900354 public static class ActivityTaskChangeCallbacks extends TestActivity {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900355 public boolean mOnDetachedFromWindowCalled = false;
356 private CountDownLatch mOnDetachedFromWindowCountDownLatch;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700357
358 @Override
359 public void onDetachedFromWindow() {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900360 mOnDetachedFromWindowCalled = true;
361 mOnDetachedFromWindowCountDownLatch.countDown();
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700362 }
363
364 void setDetachedFromWindowLatch(CountDownLatch countDownLatch) {
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900365 mOnDetachedFromWindowCountDownLatch = countDownLatch;
Yorke Leebd54c2a2016-10-25 13:49:23 -0700366 }
367 }
Jorim Jaggi7b614372016-09-28 15:17:50 +0200368}