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