| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package android.server.wm; |
| |
| import static android.app.AppOpsManager.MODE_ALLOWED; |
| import static android.app.AppOpsManager.MODE_ERRORED; |
| import static android.server.wm.ActivityManagerState.STATE_INITIALIZING; |
| import static android.server.wm.ActivityManagerState.STATE_RESUMED; |
| import static android.server.wm.ComponentNameUtils.getActivityName; |
| import static android.server.wm.UiDeviceUtils.pressHomeButton; |
| import static android.server.wm.UiDeviceUtils.pressUnlockButton; |
| import static android.server.wm.UiDeviceUtils.pressWakeupButton; |
| import static android.server.wm.backgroundactivity.appa.Components.APP_A_BACKGROUND_ACTIVITY; |
| import static android.server.wm.backgroundactivity.appa.Components.APP_A_FOREGROUND_ACTIVITY; |
| import static android.server.wm.backgroundactivity.appa.Components.APP_A_SECOND_BACKGROUND_ACTIVITY; |
| import static android.server.wm.backgroundactivity.appa.Components.APP_A_SEND_PENDING_INTENT_RECEIVER; |
| import static android.server.wm.backgroundactivity.appa.Components.APP_A_SIMPLE_ADMIN_RECEIVER; |
| import static android.server.wm.backgroundactivity.appa.Components.APP_A_START_ACTIVITY_RECEIVER; |
| import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA; |
| import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA; |
| import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA; |
| import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA; |
| import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA; |
| import static android.server.wm.backgroundactivity.appa.Components.SendPendingIntentReceiver.IS_BROADCAST_EXTRA; |
| import static android.server.wm.backgroundactivity.appa.Components.StartBackgroundActivityReceiver.START_ACTIVITY_DELAY_MS_EXTRA; |
| import static android.server.wm.backgroundactivity.appb.Components.APP_B_FOREGROUND_ACTIVITY; |
| import static android.server.wm.backgroundactivity.common.CommonComponents.EVENT_NOTIFIER_EXTRA; |
| |
| import static com.android.compatibility.common.util.SystemUtil.runShellCommand; |
| import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import android.app.ActivityManager; |
| import android.app.ActivityTaskManager; |
| import android.content.ComponentName; |
| import android.content.Intent; |
| import android.content.pm.PackageManager; |
| import android.os.ResultReceiver; |
| import android.os.SystemClock; |
| import android.platform.test.annotations.Presubmit; |
| import android.server.wm.backgroundactivity.common.CommonComponents.Event; |
| import android.server.wm.backgroundactivity.common.EventReceiver; |
| |
| import androidx.annotation.Nullable; |
| import androidx.test.InstrumentationRegistry; |
| import androidx.test.filters.FlakyTest; |
| |
| import com.android.compatibility.common.util.AppOpsUtils; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import java.util.List; |
| import java.util.concurrent.TimeoutException; |
| |
| /** |
| * This class covers all test cases for starting/blocking background activities. |
| * As instrumentation tests started by shell are whitelisted to allow starting background activity, |
| * tests can't be done in this app alone. |
| * Hence, there are 2 extra apps, appA and appB. This class will send commands to appA/appB, for |
| * example, send a broadcast to appA and ask it to start a background activity, and we will monitor |
| * the result and see if it starts an activity successfully. |
| */ |
| @Presubmit |
| public class BackgroundActivityLaunchTest extends ActivityManagerTestBase { |
| |
| private static final int ACTIVITY_FOCUS_TIMEOUT_MS = 3000; |
| private static final String APP_A_PACKAGE_NAME = APP_A_FOREGROUND_ACTIVITY.getPackageName(); |
| |
| private static final String TEST_PACKAGE_APP_A = "android.server.wm.backgroundactivity.appa"; |
| private static final String TEST_PACKAGE_APP_B = "android.server.wm.backgroundactivity.appb"; |
| |
| /** |
| * Tests can be executed as soon as the device has booted. When that happens the broadcast queue |
| * is long and it takes some time to process the broadcast we just sent. |
| */ |
| private static final int BROADCAST_DELIVERY_TIMEOUT_MS = 25000; |
| |
| @Before |
| public void setUp() throws Exception { |
| mContext = InstrumentationRegistry.getContext(); |
| mAm = mContext.getSystemService(ActivityManager.class); |
| mAtm = mContext.getSystemService(ActivityTaskManager.class); |
| |
| // disable SAW appopp for AppA (it's granted autonatically when installed in CTS) |
| AppOpsUtils.setOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window", MODE_ERRORED); |
| assertEquals(AppOpsUtils.getOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window"), |
| MODE_ERRORED); |
| |
| pressWakeupButton(); |
| pressUnlockButton(); |
| removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME); |
| assertNull(mAmWmState.getAmState().getTaskByActivity(APP_A_BACKGROUND_ACTIVITY)); |
| assertNull(mAmWmState.getAmState().getTaskByActivity(APP_A_FOREGROUND_ACTIVITY)); |
| assertNull(mAmWmState.getAmState().getTaskByActivity(APP_B_FOREGROUND_ACTIVITY)); |
| |
| runShellCommand("cmd deviceidle tempwhitelist -d 100000 " |
| + APP_A_FOREGROUND_ACTIVITY.getPackageName()); |
| runShellCommand("cmd deviceidle tempwhitelist -d 100000 " |
| + APP_B_FOREGROUND_ACTIVITY.getPackageName()); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| stopTestPackage(TEST_PACKAGE_APP_A); |
| stopTestPackage(TEST_PACKAGE_APP_B); |
| pressHomeButton(); |
| AppOpsUtils.reset(APP_A_PACKAGE_NAME); |
| mAmWmState.waitForHomeActivityVisible(); |
| runWithShellPermissionIdentity(() -> { |
| runShellCommand("dpm remove-active-admin --user current " |
| + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString()); |
| }); |
| // TODO(b/130169434): Remove it when app switch protection bug is fixed |
| SystemClock.sleep(5000); |
| } |
| |
| @Test |
| public void testBackgroundActivityBlocked() throws Exception { |
| // Start AppA background activity and blocked |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_START_ACTIVITY_RECEIVER); |
| mContext.sendBroadcast(intent); |
| boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertFalse("Should not able to launch background activity", result); |
| assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); |
| |
| // TODO(b/137134312): Bring this back once the stacks leakage issue is fixed |
| // Make sure aborting activity starts won't have any empty task/stack leaks. |
| // List<ActivityManagerState.ActivityStack> stacks = mAmWmState.getAmState().getStacks(); |
| // for (ActivityManagerState.ActivityStack stack : stacks) { |
| // assertThat(stack.getTopTask()).isNotNull(); |
| // List<ActivityManagerState.ActivityTask> tasks = stack.getTasks(); |
| // for (ActivityManagerState.ActivityTask task : tasks) { |
| // assertThat(task.getActivities().size()).isGreaterThan(0); |
| // } |
| // } |
| } |
| |
| @Test |
| public void testBackgroundActivityNotBlockedWhenSystemAlertWindowGranted() throws Exception { |
| // enable appopp for SAW for this test |
| AppOpsUtils.setOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window", MODE_ALLOWED); |
| assertEquals(AppOpsUtils.getOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window"), |
| MODE_ALLOWED); |
| |
| // Start AppA background activity successfully as the package has SAW |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_START_ACTIVITY_RECEIVER); |
| mContext.sendBroadcast(intent); |
| boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertTrue("Not able to start foreground activity", result); |
| } |
| |
| @Test |
| public void testBackgroundActivityNotBlockedWhenForegroundActivityExists() throws Exception { |
| // Start AppA foreground activity |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| mContext.startActivity(intent); |
| boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); |
| assertTrue("Not able to start foreground activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| |
| // Start AppA background activity successfully as there's a foreground activity |
| intent = new Intent(); |
| intent.setComponent(APP_A_START_ACTIVITY_RECEIVER); |
| mContext.sendBroadcast(intent); |
| result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertTrue("Not able to launch background activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY); |
| } |
| |
| @Test |
| public void testActivityNotBlockedWhenForegroundActivityLaunch() throws Exception { |
| // Start foreground activity, and foreground activity able to launch background activity |
| // successfully |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true); |
| mContext.startActivity(intent); |
| boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertTrue("Not able to launch background activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY}, |
| APP_A_FOREGROUND_ACTIVITY); |
| } |
| |
| @Test |
| public void testActivityNotBlockedwhenForegroundActivityLaunchInSameTask() throws Exception { |
| // Start foreground activity, and foreground activity able to launch background activity |
| // successfully |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true); |
| intent.putExtra(START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA, 7000); |
| mContext.startActivity(intent); |
| boolean result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS, |
| APP_A_FOREGROUND_ACTIVITY); |
| assertTrue("Not able to launch background activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| |
| // The foreground activity will be paused but will attempt to restart itself in onPause() |
| pressHomeButton(); |
| mAmWmState.waitForHomeActivityVisible(); |
| |
| // Any activity launch will be blocked for 5s because of app switching protection. |
| SystemClock.sleep(7000); |
| |
| result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); |
| assertFalse("Previously foreground Activity should not be able to relaunch itself", result); |
| result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertFalse("Previously foreground Activity should not be able to relaunch itself", result); |
| assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY}, |
| APP_A_FOREGROUND_ACTIVITY); |
| } |
| |
| @Test |
| public void testActivityNotBlockedWhenForegroundActivityLaunchInDifferentTask() |
| throws Exception { |
| // Start foreground activity, and foreground activity able to launch background activity |
| // successfully |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true); |
| intent.putExtra(START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA, 7000); |
| intent.putExtra(START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA, true); |
| mContext.startActivity(intent); |
| boolean result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS, |
| APP_A_FOREGROUND_ACTIVITY); |
| assertTrue("Not able to launch background activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| |
| // The foreground activity will be paused but will attempt to restart itself in onPause() |
| pressHomeButton(); |
| mAmWmState.waitForHomeActivityVisible(); |
| |
| // Any activity launch will be blocked for 5s because of app switching protection. |
| SystemClock.sleep(7000); |
| |
| result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); |
| assertFalse("Previously foreground Activity should not be able to relaunch itself", result); |
| result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertFalse("Previously foreground Activity should not be able to relaunch itself", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 130800326) |
| public void testActivityBlockedWhenForegroundActivityRestartsItself() throws Exception { |
| // Start AppA foreground activity |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| intent.putExtra(RELAUNCH_FOREGROUND_ACTIVITY_EXTRA, true); |
| mContext.startActivity(intent); |
| boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); |
| assertTrue("Not able to start foreground activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| |
| // The foreground activity will be paused but will attempt to restart itself in onPause() |
| pressHomeButton(); |
| mAmWmState.waitForHomeActivityVisible(); |
| |
| // Any activity launch will be blocked for 5s because of app switching protection. |
| SystemClock.sleep(5000); |
| |
| result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); |
| assertFalse("Previously foreground Activity should not be able to relaunch itself", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| } |
| |
| @Test |
| public void testSecondActivityNotBlockedWhenForegroundActivityLaunch() throws Exception { |
| // Start AppA foreground activity, which will immediately launch one activity |
| // and then the second. |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true); |
| intent.putExtra(LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA, true); |
| mContext.startActivity(intent); |
| |
| boolean result = waitForActivityFocused(APP_A_SECOND_BACKGROUND_ACTIVITY); |
| assertTrue("Not able to launch second background activity", result); |
| |
| waitAndAssertActivityState(APP_A_BACKGROUND_ACTIVITY, STATE_INITIALIZING, |
| "First activity should have been created"); |
| assertTaskStack( |
| new ComponentName[]{APP_A_SECOND_BACKGROUND_ACTIVITY, APP_A_BACKGROUND_ACTIVITY, |
| APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| } |
| |
| @Test |
| public void testPendingIntentActivityBlocked() throws Exception { |
| // Cannot start activity by pending intent, as both appA and appB are in background |
| sendPendingIntentActivity(); |
| boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertFalse("Should not able to launch background activity", result); |
| assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 130800326) |
| public void testPendingIntentActivityNotBlocked_appAIsForeground() throws Exception { |
| // Start AppA foreground activity |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| mContext.startActivity(intent); |
| boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY); |
| assertTrue("Not able to start foreground Activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| |
| // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start |
| // activity in App A |
| sendPendingIntentActivity(); |
| result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertTrue("Not able to launch background activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY); |
| assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY); |
| } |
| |
| @Test |
| public void testPendingIntentBroadcastActivityNotBlocked_appBIsForeground() throws Exception { |
| // Start AppB foreground activity |
| Intent intent = new Intent(); |
| intent.setComponent(APP_B_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| mContext.startActivity(intent); |
| boolean result = waitForActivityFocused(APP_B_FOREGROUND_ACTIVITY); |
| assertTrue("Not able to start foreground Activity", result); |
| assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY); |
| |
| // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start |
| // activity in App A |
| sendPendingIntentActivity(); |
| result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertTrue("Not able to launch background activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY); |
| assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY); |
| } |
| |
| @Test |
| public void testPendingIntentBroadcastTimeout_noDelay() throws Exception { |
| assertPendingIntentBroadcastTimeoutTest(0, true); |
| } |
| |
| @Test |
| public void testPendingIntentBroadcastTimeout_delay1s() throws Exception { |
| assertPendingIntentBroadcastTimeoutTest(1000, true); |
| } |
| |
| @Test |
| public void testPendingIntentBroadcastTimeout_delay12s() throws Exception { |
| assertPendingIntentBroadcastTimeoutTest(12000, false); |
| } |
| |
| @Test |
| public void testPendingIntentBroadcast_appBIsBackground() throws Exception { |
| EventReceiver receiver = new EventReceiver( |
| Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED); |
| |
| // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start |
| // activity in App A |
| sendPendingIntentBroadcast(0, receiver.getNotifier()); |
| |
| // Waits for final hoop in AppA to start looking for activity, otherwise it could succeed |
| // if the broadcast took long time to get executed (which may happen after boot). |
| receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS); |
| boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertFalse("Should not able to launch background activity", result); |
| assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); |
| } |
| |
| @Test |
| public void testDeviceOwner() throws Exception { |
| // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start |
| // activity in App A |
| if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) { |
| return; |
| } |
| |
| String cmdResult = runShellCommand("dpm set-device-owner --user cur " |
| + APP_A_SIMPLE_ADMIN_RECEIVER.flattenToString()); |
| assertThat(cmdResult).contains("Success"); |
| EventReceiver receiver = new EventReceiver( |
| Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED); |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_START_ACTIVITY_RECEIVER); |
| intent.putExtra(EVENT_NOTIFIER_EXTRA, receiver.getNotifier()); |
| |
| mContext.sendBroadcast(intent); |
| |
| // Waits for final hoop in AppA to start looking for activity |
| receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS); |
| boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY); |
| assertTrue("Not able to launch background activity", result); |
| assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY); |
| } |
| |
| private void assertTaskStack(ComponentName[] expectedComponents, |
| ComponentName sourceComponent) { |
| if (expectedComponents == null) { |
| assertNull(mAmWmState.getAmState().getTaskByActivity(sourceComponent)); |
| return; |
| } |
| List<ActivityManagerState.Activity> actual = mAmWmState.getAmState().getTaskByActivity( |
| sourceComponent).mActivities; |
| assertEquals(expectedComponents.length, actual.size()); |
| int size = expectedComponents.length; |
| for (int i = 0; i < size; i++) { |
| assertEquals(expectedComponents[i].flattenToShortString(), actual.get(i).getName()); |
| } |
| } |
| |
| private void assertPendingIntentBroadcastTimeoutTest(int delayMs, boolean expectedResult) |
| throws TimeoutException { |
| // Start AppB foreground activity |
| Intent intent = new Intent(); |
| intent.setComponent(APP_B_FOREGROUND_ACTIVITY); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| mContext.startActivity(intent); |
| boolean result = waitForActivityFocused(APP_B_FOREGROUND_ACTIVITY); |
| assertTrue("Not able to start foreground Activity", result); |
| assertTaskStack(new ComponentName[]{APP_B_FOREGROUND_ACTIVITY}, APP_B_FOREGROUND_ACTIVITY); |
| EventReceiver receiver = new EventReceiver( |
| Event.APP_A_START_BACKGROUND_ACTIVITY_BROADCAST_RECEIVED); |
| |
| // Send pendingIntent from AppA to AppB, and the AppB launch the pending intent to start |
| // activity in App A |
| sendPendingIntentBroadcast(delayMs, receiver.getNotifier()); |
| |
| // Waits for final hoop in AppA to start looking for activity |
| receiver.waitForEventOrThrow(BROADCAST_DELIVERY_TIMEOUT_MS); |
| result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS + delayMs, |
| APP_A_BACKGROUND_ACTIVITY); |
| assertEquals(expectedResult, result); |
| if (expectedResult) { |
| assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, |
| APP_A_BACKGROUND_ACTIVITY); |
| } else { |
| assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY); |
| } |
| } |
| |
| private boolean waitForActivityFocused(ComponentName componentName) { |
| return waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS, componentName); |
| } |
| |
| // Return true if the activity is shown before timeout |
| private boolean waitForActivityFocused(int timeoutMs, ComponentName componentName) { |
| long endTime = System.currentTimeMillis() + timeoutMs; |
| while (endTime > System.currentTimeMillis()) { |
| mAmWmState.getAmState().computeState(); |
| mAmWmState.getWmState().computeState(); |
| if (mAmWmState.getAmState().hasActivityState(componentName, STATE_RESUMED)) { |
| SystemClock.sleep(200); |
| mAmWmState.getAmState().computeState(); |
| mAmWmState.getWmState().computeState(); |
| break; |
| } |
| SystemClock.sleep(200); |
| mAmWmState.getAmState().computeState(); |
| mAmWmState.getWmState().computeState(); |
| } |
| return getActivityName(componentName).equals(mAmWmState.getAmState().getFocusedActivity()); |
| } |
| |
| private void sendPendingIntentActivity() { |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_SEND_PENDING_INTENT_RECEIVER); |
| intent.putExtra(IS_BROADCAST_EXTRA, false); |
| mContext.sendBroadcast(intent); |
| } |
| |
| private void sendPendingIntentBroadcast(int delayMs, @Nullable ResultReceiver eventNotifier) { |
| Intent intent = new Intent(); |
| intent.setComponent(APP_A_SEND_PENDING_INTENT_RECEIVER); |
| intent.putExtra(IS_BROADCAST_EXTRA, true); |
| if (delayMs > 0) { |
| intent.putExtra(START_ACTIVITY_DELAY_MS_EXTRA, delayMs); |
| } |
| intent.putExtra(EVENT_NOTIFIER_EXTRA, eventNotifier); |
| mContext.sendBroadcast(intent); |
| } |
| } |