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