1 /* 2 * Copyright 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 17 package com.android.managedprovisioning.provisioning; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 22 import static android.app.admin.DevicePolicyManager.ACTION_STATE_USER_SETUP_COMPLETE; 23 24 import static androidx.test.espresso.Espresso.onView; 25 import static androidx.test.espresso.Espresso.pressBack; 26 import static androidx.test.espresso.action.ViewActions.click; 27 import static androidx.test.espresso.assertion.ViewAssertions.matches; 28 import static androidx.test.espresso.intent.Intents.intended; 29 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction; 30 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent; 31 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; 32 import static androidx.test.espresso.matcher.ViewMatchers.withId; 33 import static androidx.test.espresso.matcher.ViewMatchers.withParent; 34 import static androidx.test.espresso.matcher.ViewMatchers.withText; 35 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 36 37 import static com.google.common.truth.Truth.assertThat; 38 39 import static org.hamcrest.Matchers.not; 40 import static org.hamcrest.core.AllOf.allOf; 41 import static org.junit.Assert.assertFalse; 42 import static org.junit.Assert.assertTrue; 43 import static org.mockito.Matchers.any; 44 import static org.mockito.Matchers.anyString; 45 import static org.mockito.Matchers.eq; 46 import static org.mockito.Mockito.doNothing; 47 import static org.mockito.Mockito.doReturn; 48 import static org.mockito.Mockito.mockingDetails; 49 import static org.mockito.Mockito.reset; 50 import static org.mockito.Mockito.spy; 51 import static org.mockito.Mockito.timeout; 52 import static org.mockito.Mockito.verify; 53 import static org.mockito.Mockito.when; 54 55 import android.Manifest.permission; 56 import android.content.ComponentName; 57 import android.content.Context; 58 import android.content.Intent; 59 import android.content.pm.ActivityInfo; 60 import android.content.pm.PackageManager; 61 import android.content.pm.ResolveInfo; 62 import android.graphics.Color; 63 import android.os.Bundle; 64 import android.os.RemoteException; 65 import android.provider.Settings; 66 67 import androidx.test.InstrumentationRegistry; 68 import androidx.test.espresso.intent.Intents; 69 import androidx.test.espresso.intent.rule.IntentsTestRule; 70 import androidx.test.filters.SmallTest; 71 import androidx.test.uiautomator.UiDevice; 72 73 import com.android.managedprovisioning.R; 74 import com.android.managedprovisioning.TestInstrumentationRunner; 75 import com.android.managedprovisioning.TestUtils; 76 import com.android.managedprovisioning.common.PolicyComplianceUtils; 77 import com.android.managedprovisioning.common.SettingsFacade; 78 import com.android.managedprovisioning.common.ThemeHelper; 79 import com.android.managedprovisioning.common.ThemeHelper.DefaultNightModeChecker; 80 import com.android.managedprovisioning.common.ThemeHelper.DefaultSetupWizardBridge; 81 import com.android.managedprovisioning.common.Utils; 82 import com.android.managedprovisioning.finalization.UserProvisioningStateHelper; 83 import com.android.managedprovisioning.model.ProvisioningParams; 84 85 import com.google.common.collect.Iterables; 86 87 import junit.framework.AssertionFailedError; 88 89 import org.junit.After; 90 import org.junit.AfterClass; 91 import org.junit.Before; 92 import org.junit.BeforeClass; 93 import org.junit.Ignore; 94 import org.junit.Rule; 95 import org.junit.Test; 96 import org.junit.runner.RunWith; 97 import org.mockito.Mock; 98 import org.mockito.hamcrest.MockitoHamcrest; 99 import org.mockito.invocation.Invocation; 100 import org.mockito.junit.MockitoJUnitRunner; 101 102 import java.lang.reflect.Method; 103 import java.util.ArrayList; 104 import java.util.Collection; 105 import java.util.List; 106 107 /** 108 * Unit tests for {@link ProvisioningActivity}. 109 */ 110 @SmallTest 111 @RunWith(MockitoJUnitRunner.class) 112 public class ProvisioningActivityTest { 113 114 private static final String ADMIN_PACKAGE = "com.test.admin"; 115 private static final String TEST_PACKAGE = "com.android.managedprovisioning.tests"; 116 private static final ComponentName ADMIN = new ComponentName(ADMIN_PACKAGE, ".Receiver"); 117 private static final ComponentName TEST_ACTIVITY = new ComponentName(TEST_PACKAGE, 118 EmptyActivity.class.getCanonicalName()); 119 public static final ProvisioningParams PROFILE_OWNER_PARAMS = new ProvisioningParams.Builder() 120 .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE) 121 .setDeviceAdminComponentName(ADMIN) 122 .build(); 123 public static final ProvisioningParams DEVICE_OWNER_PARAMS = new ProvisioningParams.Builder() 124 .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE) 125 .setDeviceAdminComponentName(ADMIN) 126 .build(); 127 private static final ProvisioningParams FINANCED_DEVICE_PARAMS = new ProvisioningParams 128 .Builder() 129 .setProvisioningAction(ACTION_PROVISION_FINANCED_DEVICE) 130 .setDeviceAdminComponentName(ADMIN) 131 .build(); 132 private static final ProvisioningParams NFC_PARAMS = new ProvisioningParams.Builder() 133 .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE) 134 .setDeviceAdminComponentName(ADMIN) 135 .setStartedByTrustedSource(true) 136 .setIsNfc(true) 137 .build(); 138 private static final Intent PROFILE_OWNER_INTENT = new Intent() 139 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, PROFILE_OWNER_PARAMS); 140 private static final Intent DEVICE_OWNER_INTENT = new Intent() 141 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, DEVICE_OWNER_PARAMS); 142 private static final Intent FINANCED_DEVICE_INTENT = new Intent() 143 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, FINANCED_DEVICE_PARAMS); 144 private static final Intent NFC_INTENT = new Intent() 145 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, NFC_PARAMS); 146 private static final int DEFAULT_LOGO_COLOR = Color.rgb(1, 2, 3); 147 private static final int BROADCAST_TIMEOUT = 1000; 148 private static final int WAIT_PROVISIONING_COMPLETE_MILLIS = 60_000; 149 150 private static class CustomIntentsTestRule extends IntentsTestRule<ProvisioningActivity> { 151 private boolean mIsActivityRunning = false; CustomIntentsTestRule()152 private CustomIntentsTestRule() { 153 super(ProvisioningActivity.class, true /* Initial touch mode */, 154 false /* Lazily launch activity */); 155 } 156 157 @Override afterActivityLaunched()158 protected synchronized void afterActivityLaunched() { 159 mIsActivityRunning = true; 160 super.afterActivityLaunched(); 161 } 162 163 @Override afterActivityFinished()164 public synchronized void afterActivityFinished() { 165 // Temp fix for b/37663530 166 if (mIsActivityRunning) { 167 super.afterActivityFinished(); 168 mIsActivityRunning = false; 169 } 170 } 171 } 172 173 @Rule 174 public CustomIntentsTestRule mActivityRule = new CustomIntentsTestRule(); 175 176 @Mock private ProvisioningManager mProvisioningManager; 177 @Mock private PackageManager mPackageManager; 178 @Mock private UserProvisioningStateHelper mUserProvisioningStateHelper; 179 @Mock private PolicyComplianceUtils mPolicyComplianceUtils; 180 @Mock private SettingsFacade mSettingsFacade; 181 182 private Utils mUtils; 183 private static int mRotationLocked; 184 private final ThemeHelper mThemeHelper = 185 new ThemeHelper(new DefaultNightModeChecker(), new DefaultSetupWizardBridge()); 186 187 @BeforeClass setUpClass()188 public static void setUpClass() { 189 // Stop the activity from rotating in order to keep hold of the context 190 Context context = InstrumentationRegistry.getTargetContext(); 191 192 mRotationLocked = Settings.System.getInt(context.getContentResolver(), 193 Settings.System.ACCELEROMETER_ROTATION, 0); 194 Settings.System.putInt(context.getContentResolver(), 195 Settings.System.ACCELEROMETER_ROTATION, 0); 196 } 197 198 @Before setup()199 public void setup() throws RemoteException { 200 mUtils = spy(new Utils()); 201 doNothing().when(mUtils).factoryReset(any(Context.class), anyString()); 202 doReturn(DEFAULT_LOGO_COLOR).when(mUtils).getAccentColor(any()); 203 TestUtils.wakeupDeviceAndPressHome(UiDevice.getInstance(getInstrumentation())); 204 } 205 206 @AfterClass tearDownClass()207 public static void tearDownClass() { 208 // Reset the rotation value back to what it was before the test 209 Context context = InstrumentationRegistry.getTargetContext(); 210 211 Settings.System.putInt(context.getContentResolver(), 212 Settings.System.ACCELEROMETER_ROTATION, mRotationLocked); 213 } 214 215 @Before setUp()216 public void setUp() { 217 TestInstrumentationRunner.registerReplacedActivity(ProvisioningActivity.class, 218 (classLoader, className, intent) -> 219 new ProvisioningActivity( 220 mProvisioningManager, mUtils, mUserProvisioningStateHelper, 221 mPolicyComplianceUtils, mSettingsFacade, mThemeHelper) { 222 @Override 223 public PackageManager getPackageManager() { 224 return mPackageManager; 225 } 226 }); 227 } 228 229 @After tearDown()230 public void tearDown() { 231 TestInstrumentationRunner.unregisterReplacedActivity(ProvisioningActivity.class); 232 } 233 234 @Ignore("b/181323689") 235 @Test testLaunch()236 public void testLaunch() throws NoSuchMethodException { 237 // GIVEN the activity was launched with a profile owner intent 238 launchActivityAndWait(PROFILE_OWNER_INTENT); 239 // THEN the provisioning process should be initiated 240 verify(mProvisioningManager).maybeStartProvisioning(PROFILE_OWNER_PARAMS); 241 242 // THEN the activity should start listening for provisioning updates 243 final Method registerListenerMethod = ProvisioningManager.class 244 .getMethod("registerListener", ProvisioningManagerCallback.class); 245 final int registerListenerInvocations = getNumberOfInvocations(registerListenerMethod); 246 final Method unregisterListenerMethod = ProvisioningManager.class 247 .getMethod("unregisterListener", ProvisioningManagerCallback.class); 248 final int unregisterListenerInvocations = getNumberOfInvocations(unregisterListenerMethod); 249 assertThat(registerListenerInvocations - unregisterListenerInvocations).isEqualTo(1); 250 } 251 getNumberOfInvocations(Method method)252 private int getNumberOfInvocations(Method method) { 253 final Collection<Invocation> invocations = 254 mockingDetails(mProvisioningManager).getInvocations(); 255 return (int) invocations.stream() 256 .filter(invocation -> invocation.getMethod().equals(method)).count(); 257 } 258 259 @Ignore("b/181323689") 260 @Test testSavedInstanceState()261 public void testSavedInstanceState() throws Throwable { 262 // GIVEN the activity was launched with a profile owner intent 263 launchActivityAndWait(PROFILE_OWNER_INTENT); 264 265 // THEN the provisioning process should be initiated 266 verify(mProvisioningManager).maybeStartProvisioning(PROFILE_OWNER_PARAMS); 267 268 // WHEN the activity is recreated with a saved instance state 269 mActivityRule.runOnUiThread(() -> { 270 Bundle bundle = new Bundle(); 271 InstrumentationRegistry.getInstrumentation() 272 .callActivityOnSaveInstanceState(mActivityRule.getActivity(), bundle); 273 mActivityRule.getActivity().recreate(); 274 }); 275 276 // THEN provisioning is attempted to be started again 277 verify(mProvisioningManager).maybeStartProvisioning(PROFILE_OWNER_PARAMS); 278 } 279 280 @Ignore("b/181323689") 281 @Test testPause()282 public void testPause() throws Throwable { 283 // GIVEN the activity was launched with a profile owner intent 284 launchActivityAndWait(PROFILE_OWNER_INTENT); 285 286 reset(mProvisioningManager); 287 288 // WHEN the activity is paused 289 mActivityRule.runOnUiThread(() -> { 290 InstrumentationRegistry.getInstrumentation() 291 .callActivityOnPause(mActivityRule.getActivity()); 292 }); 293 294 // THEN the listener is unregistered 295 // b/130350469 to figure out why onPause/onResume is called one additional time 296 verify(mProvisioningManager).unregisterListener(any(ProvisioningManagerCallback.class)); 297 } 298 299 @Ignore("b/181323689") 300 @Test testCancelDeviceOwner()301 public void testCancelDeviceOwner() throws Throwable { 302 // GIVEN the activity was launched with a device owner intent 303 launchActivityAndWait(DEVICE_OWNER_INTENT); 304 305 // WHEN the user tries to cancel 306 pressBack(); 307 308 // THEN the cancel dialog should be shown 309 onView(withText(R.string.stop_setup_reset_device_question)).check(matches(isDisplayed())); 310 onView(withText(R.string.this_will_reset_take_back_first_screen)) 311 .check(matches(isDisplayed())); 312 313 // WHEN deciding not to cancel 314 onView(withId(android.R.id.button2)) 315 .check(matches(withText(R.string.device_owner_cancel_cancel))) 316 .perform(click()); 317 318 // THEN the activity should not be finished 319 assertFalse(mActivityRule.getActivity().isFinishing()); 320 321 // WHEN the user tries to cancel 322 pressBack(); 323 324 // THEN the cancel dialog should be shown 325 onView(withText(R.string.stop_setup_reset_device_question)).check(matches(isDisplayed())); 326 327 // WHEN deciding to cancel 328 onView(withId(android.R.id.button1)) 329 .check(matches(withText(R.string.reset))) 330 .perform(click()); 331 332 // THEN factory reset should be invoked 333 verify(mUtils, timeout(BROADCAST_TIMEOUT)).factoryReset(any(Context.class), anyString()); 334 } 335 336 @Ignore("b/181323689") 337 @Test testSuccess()338 public void testSuccess() throws Throwable { 339 // GIVEN the activity was launched with a profile owner intent 340 launchActivityAndWait(PROFILE_OWNER_INTENT); 341 342 // WHEN preFinalization is completed 343 mActivityRule.runOnUiThread(() -> mActivityRule.getActivity().preFinalizationCompleted()); 344 345 Thread.sleep(WAIT_PROVISIONING_COMPLETE_MILLIS); 346 347 // Press next button on provisioning complete 348 onView(withText(R.string.next)).perform(click()); 349 350 // THEN the activity should finish 351 assertTrue(mActivityRule.getActivity().isFinishing()); 352 } 353 354 @Ignore("b/181323689") 355 @Test testSuccess_Nfc()356 public void testSuccess_Nfc() throws Throwable { 357 // GIVEN queryIntentActivities return test_activity 358 ActivityInfo activityInfo = new ActivityInfo(); 359 activityInfo.packageName = TEST_ACTIVITY.getPackageName(); 360 activityInfo.name = TEST_ACTIVITY.getClassName(); 361 activityInfo.permission = permission.BIND_DEVICE_ADMIN; 362 ResolveInfo resolveInfo = new ResolveInfo(); 363 resolveInfo.activityInfo = activityInfo; 364 List<ResolveInfo> resolveInfoList = new ArrayList(); 365 resolveInfoList.add(resolveInfo); 366 when(mPackageManager.queryIntentActivities( 367 MockitoHamcrest.argThat(hasAction(ACTION_STATE_USER_SETUP_COMPLETE)), 368 eq(0))).thenReturn(resolveInfoList); 369 when(mPackageManager.checkPermission(eq(permission.DISPATCH_PROVISIONING_MESSAGE), 370 eq(activityInfo.packageName))).thenReturn(PackageManager.PERMISSION_GRANTED); 371 when(mPolicyComplianceUtils.isPolicyComplianceActivityResolvableForUser( 372 any(), any(), any(), any())).thenReturn(true); 373 374 // GIVEN the activity was launched with a nfc intent 375 launchActivityAndWait(NFC_INTENT); 376 377 // WHEN preFinalization is completed 378 mActivityRule.runOnUiThread(() -> mActivityRule.getActivity().preFinalizationCompleted()); 379 380 Thread.sleep(WAIT_PROVISIONING_COMPLETE_MILLIS); 381 382 // Press next button on provisioning complete 383 onView(withText(R.string.next)).perform(click()); 384 385 // THEN verify starting TEST_ACTIVITY 386 intended(allOf(hasComponent(TEST_ACTIVITY), hasAction(ACTION_STATE_USER_SETUP_COMPLETE))); 387 388 // THEN the activity should finish 389 assertTrue(mActivityRule.getActivity().isFinishing()); 390 } 391 392 @Ignore("b/181323689") 393 @Test testInitializeUi_profileOwner()394 public void testInitializeUi_profileOwner() throws Throwable { 395 // GIVEN the activity was launched with a profile owner intent 396 launchActivityAndWait(PROFILE_OWNER_INTENT); 397 398 // THEN the profile owner description should be present 399 onView(withId(R.id.provisioning_progress)) 400 .check(matches(withText(R.string.work_profile_provisioning_progress_label))); 401 402 // THEN the animation is shown. 403 onView(withId(R.id.animation)).check(matches(isDisplayed())); 404 } 405 406 @Ignore("b/181323689") 407 @Test testInitializeUi_deviceOwner()408 public void testInitializeUi_deviceOwner() throws Throwable { 409 // GIVEN the activity was launched with a device owner intent 410 launchActivityAndWait(DEVICE_OWNER_INTENT); 411 412 // THEN the description should be empty 413 onView(withId(R.id.provisioning_progress)).check( 414 matches(withText(R.string.fully_managed_device_provisioning_progress_label))); 415 416 // THEN the animation is shown. 417 onView(withId(R.id.animation)).check(matches(isDisplayed())); 418 } 419 420 @Ignore("b/181323689") 421 @Test testInitializeUi_deviceOwnerPermissionGrantOptOut()422 public void testInitializeUi_deviceOwnerPermissionGrantOptOut() throws Throwable { 423 final ProvisioningParams deviceOwnerParams = new ProvisioningParams.Builder() 424 .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE) 425 .setDeviceAdminComponentName(ADMIN) 426 .setDeviceOwnerPermissionGrantOptOut(true) 427 .build(); 428 429 final Intent deviceOwnerIntent = new Intent() 430 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, deviceOwnerParams); 431 432 // GIVEN the activity was launched with a device owner intent 433 launchActivityAndWait(deviceOwnerIntent); 434 435 // THEN the description should be empty 436 onView(withId(R.id.provisioning_progress)).check( 437 matches(withText(R.string.fully_managed_device_provisioning_progress_label))); 438 439 // THEN the animation is shown. 440 onView(withId(R.id.animation)).check(matches(isDisplayed())); 441 waitForFullyManagedDeviceHeader(); 442 443 onView(withId(com.google.android.setupdesign.R.id.sud_layout_subtitle)).check(matches( 444 withText(R.string.fully_managed_device_provisioning_step_2_subheader))); 445 onView(withId(R.id.item1)).check(matches(not(isDisplayed()))); 446 onView(withId(R.id.item2)).check(matches(not(isDisplayed()))); 447 } 448 449 @Ignore("b/181323689") 450 @Test testInitializeUi_deviceOwnerDefault()451 public void testInitializeUi_deviceOwnerDefault() throws Throwable { 452 // GIVEN the activity was launched with a device owner intent 453 launchActivityAndWait(DEVICE_OWNER_INTENT); 454 455 // THEN the description should be empty 456 onView(withId(R.id.provisioning_progress)).check( 457 matches(withText(R.string.fully_managed_device_provisioning_progress_label))); 458 459 // THEN the animation is shown. 460 onView(withId(R.id.animation)).check(matches(isDisplayed())); 461 waitForFullyManagedDeviceHeader(); 462 463 onView(allOf(withId(R.id.sud_items_title), withParent(withId(R.id.item1)))) 464 .check(matches( 465 withText(R.string.fully_managed_device_provisioning_permissions_header))); 466 onView(allOf(withId(R.id.sud_items_summary), withParent(withId(R.id.item1)))) 467 .check(matches(withText( 468 R.string.fully_managed_device_provisioning_permissions_subheader))); 469 onView(allOf(withId(R.id.sud_items_title), withParent(withId(R.id.item2)))) 470 .check(matches(withText( 471 R.string.fully_managed_device_provisioning_permissions_secondary_header))); 472 onView(allOf(withId(R.id.sud_items_summary), withParent(withId(R.id.item2)))) 473 .check(matches(withText(R.string 474 .fully_managed_device_provisioning_permissions_secondary_subheader))); 475 } 476 477 @Ignore("b/181323689") 478 @Test testInitializeUi_deviceOwnerCanAbort()479 public void testInitializeUi_deviceOwnerCanAbort() throws Throwable { 480 // GIVEN the activity was launched with a device owner intent 481 launchActivityAndWait(DEVICE_OWNER_INTENT); 482 483 // THEN the description should be empty 484 onView(withId(R.id.provisioning_progress)).check( 485 matches(withText(R.string.fully_managed_device_provisioning_progress_label))); 486 487 // THEN the animation is shown. 488 onView(withId(R.id.animation)).check(matches(isDisplayed())); 489 waitForFullyManagedDeviceHeader(); 490 // WHEN preFinalization is completed 491 mActivityRule.runOnUiThread(() -> mActivityRule.getActivity().preFinalizationCompleted()); 492 // THEN the cancel button should be available. 493 waitForCancelSetupButtonAndClickIt(); 494 495 // Check 496 Intent receivedIntent = Iterables.getOnlyElement(Intents.getIntents()); 497 assertThat(receivedIntent).isNotNull(); 498 assertThat(receivedIntent.getComponent()).isEqualTo( 499 new ComponentName(InstrumentationRegistry.getTargetContext(), 500 ResetAndReturnDeviceActivity.class)); 501 assertThat(receivedIntent.hasExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS)).isTrue(); 502 assertThat(receivedIntent.hasExtra("wizardBundle")).isTrue(); 503 } 504 505 //TODO(b/180399632): Replace this wait with callbacks or another mechanism where the 506 //activity-under-test is more collaborative with the testing infrastructure to indicate 507 //its state. waitForCancelSetupButtonAndClickIt()508 private void waitForCancelSetupButtonAndClickIt() throws InterruptedException { 509 final int cancelButtonId = 3; 510 int numAttempts = 0; 511 while (numAttempts < 40) { 512 try { 513 onView(withId(cancelButtonId)) 514 .check(matches( 515 withText(R.string.fully_managed_device_cancel_setup_button))); 516 onView(withId(cancelButtonId)).check(matches(isDisplayed())); 517 break; 518 } catch (AssertionFailedError e) { 519 numAttempts++; 520 } 521 Thread.sleep(500); 522 } 523 524 // Click the cancel button. 525 onView(withId(cancelButtonId)) 526 .check(matches(withText(R.string.fully_managed_device_cancel_setup_button))) 527 .perform(click()); 528 } 529 530 @Ignore("b/181323689") 531 @Test testInitializeUi_financedDevice()532 public void testInitializeUi_financedDevice() throws Throwable { 533 // GIVEN the activity was launched with a financed device intent 534 launchActivityAndWait(FINANCED_DEVICE_INTENT); 535 536 // THEN the header will be set 537 onView(withId(com.google.android.setupdesign.R.id.suc_layout_title)) 538 .check(matches(withText(R.string.just_a_sec))); 539 540 // THEN the icon will be invisible 541 onView(withId(com.google.android.setupdesign.R.id.sud_layout_icon)) 542 .check(matches(not(isDisplayed()))); 543 544 // THEN the animation is shown. 545 onView(withId(R.id.animation)).check(matches(isDisplayed())); 546 } 547 launchActivityAndWait(Intent intent)548 private void launchActivityAndWait(Intent intent) { 549 mActivityRule.launchActivity(intent); 550 } 551 552 // TODO(b/180399632): Utilize a callback, IdlingResource, etc. waitForFullyManagedDeviceHeader()553 private void waitForFullyManagedDeviceHeader() throws InterruptedException { 554 int numAttempts = 0; 555 while (numAttempts < 40) { 556 try { 557 onView(withId(com.google.android.setupdesign.R.id.sud_layout_subtitle)) 558 .check(matches(withText( 559 R.string.fully_managed_device_provisioning_step_2_subheader))); 560 break; 561 } catch (AssertionFailedError e) { 562 numAttempts++; 563 } 564 Thread.sleep(500); 565 } 566 } 567 } 568