1 /* 2 * Copyright (C) 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 package com.android.managedprovisioning.e2eui; 17 18 import static androidx.test.espresso.Espresso.onView; 19 import static androidx.test.espresso.action.ViewActions.click; 20 import static androidx.test.espresso.matcher.ViewMatchers.withClassName; 21 import static androidx.test.espresso.matcher.ViewMatchers.withText; 22 23 import static org.hamcrest.Matchers.allOf; 24 import static org.hamcrest.Matchers.containsString; 25 26 import android.content.Intent; 27 import android.content.pm.UserInfo; 28 import android.os.SystemClock; 29 import android.os.UserManager; 30 import android.test.AndroidTestCase; 31 import android.util.Log; 32 import android.view.View; 33 34 import androidx.test.espresso.ViewInteraction; 35 import androidx.test.espresso.base.DefaultFailureHandler; 36 import androidx.test.filters.LargeTest; 37 import androidx.test.rule.ActivityTestRule; 38 39 import com.android.managedprovisioning.R; 40 import com.android.managedprovisioning.TestInstrumentationRunner; 41 import com.android.managedprovisioning.common.BlockingBroadcastReceiver; 42 import com.android.managedprovisioning.preprovisioning.PreProvisioningActivity; 43 44 import com.google.android.setupcompat.template.FooterButton; 45 46 import org.hamcrest.Matcher; 47 48 import java.util.List; 49 50 @LargeTest 51 public class ManagedProfileTest extends AndroidTestCase { 52 private static final String TAG = "ManagedProfileTest"; 53 54 private static final long PROVISIONING_RESULT_TIMEOUT_SECONDS = 120L; 55 private static final long FIVE_SECONDS_MILLIS = 5000; 56 57 public ActivityTestRule mActivityRule; 58 private ProvisioningResultListener mResultListener; 59 60 @Override setUp()61 protected void setUp() throws Exception { 62 super.setUp(); 63 mActivityRule = new ActivityTestRule<>( 64 PreProvisioningActivity.class, 65 true /* initialTouchMode */, 66 false); // launchActivity. False to set intent per method 67 mResultListener = new ProvisioningResultListener(getContext()); 68 TestInstrumentationRunner.registerReplacedActivity(PreProvisioningActivity.class, 69 (cl, className, intent) -> new TestPreProvisioningActivity(mResultListener)); 70 } 71 72 @Override tearDown()73 protected void tearDown() throws Exception { 74 super.tearDown(); 75 TestInstrumentationRunner.unregisterReplacedActivity(PreProvisioningActivity.class); 76 mResultListener.unregister(); 77 78 // Remove any managed profiles in case that 79 removeAllManagedProfiles(); 80 } 81 removeAllManagedProfiles()82 private void removeAllManagedProfiles() { 83 UserManager um = getContext().getSystemService(UserManager.class); 84 List<UserInfo> users = um.getUsers(); 85 for (UserInfo user : users) { 86 if (user.isManagedProfile()) { 87 int userId = user.getUserHandle().getIdentifier(); 88 removeProfileAndWait(userId); 89 } 90 } 91 } 92 93 /** Remove a profile and wait until it has been removed before continuing. */ removeProfileAndWait(int userId)94 private void removeProfileAndWait(int userId) { 95 Log.e(TAG, "remove managed profile user: " + userId); 96 UserManager userManager = getContext().getSystemService(UserManager.class); 97 98 // Intent.ACTION_MANAGED_PROFILE_REMOVED gets sent too early, so we need to wait for 99 // Intent.ACTION_USER_REMOVED 100 BlockingBroadcastReceiver receiver = 101 new BlockingBroadcastReceiver(mContext, Intent.ACTION_USER_REMOVED); 102 try { 103 receiver.register(); 104 userManager.removeUserEvenWhenDisallowed(userId); 105 106 long timeoutMillis = PROVISIONING_RESULT_TIMEOUT_SECONDS * 1000; 107 Intent confirmation = receiver.awaitForBroadcast(timeoutMillis); 108 109 if (confirmation == null) { 110 // The user was not removed 111 fail("Waiting for profile to be removed, but was not removed."); 112 } 113 } finally { 114 receiver.unregisterQuietly(); 115 } 116 } 117 118 // TODO(b/151421429): investigate why this test fails 119 // public void testManagedProfile() throws Exception { 120 // mActivityRule.launchActivity(ManagedProfileAdminReceiver.INTENT_PROVISION_MANAGED_PROFILE); 121 // 122 // // Try pressing "Accept & continue" for 1 minute (12 * 5 seconds) 123 // new EspressoClickRetryActions(/* retries= */ 12, /* delayMillis= */ FIVE_SECONDS_MILLIS) { 124 // @Override 125 // public ViewInteraction newViewInteraction1() { 126 // return onView(allOf(withClassName(containsString("FooterActionButton")), 127 // withText(R.string.accept_and_continue))); 128 // } 129 // }.run(); 130 // 131 // mResultListener.register(); 132 // 133 // // Try pressing "Next" for 10 minutes (120 * 5 seconds). This must be long enough for 134 // // DPC download/installation to happen, and education screens to complete. 135 // new EspressoClickRetryActions(/* retries= */ 120, /* delayMillis= */ FIVE_SECONDS_MILLIS) { 136 // @Override 137 // public ViewInteraction newViewInteraction1() { 138 // return onView(allOf(withClassName(containsString("FooterActionButton")), 139 // withText(R.string.next))); 140 // } 141 // }.run(); 142 // 143 // // Try pressing "Next" for 10 minutes (5 * 5 seconds). This must be long enough to show the 144 // // cross profile consent screen. 145 // new EspressoClickRetryActions(/* retries= */ 5, /* delayMillis= */ FIVE_SECONDS_MILLIS) { 146 // @Override 147 // public ViewInteraction newViewInteraction1() { 148 // return onView(allOf(withClassName(containsString("FooterActionButton")), 149 // withText(R.string.next))); 150 // } 151 // }.run(); 152 // 153 // if (mResultListener.await(PROVISIONING_RESULT_TIMEOUT_SECONDS)) { 154 // assertTrue(mResultListener.getResult()); 155 // } else { 156 // fail("timeout: " + PROVISIONING_RESULT_TIMEOUT_SECONDS + " seconds"); 157 // } 158 // } 159 160 private abstract class EspressoClickRetryActions { 161 private final int mRetries; 162 private final long mDelayMillis; 163 private int i = 0; 164 EspressoClickRetryActions(int retries, long delayMillis)165 EspressoClickRetryActions(int retries, long delayMillis) { 166 mRetries = retries; 167 mDelayMillis = delayMillis; 168 } 169 newViewInteraction1()170 public abstract ViewInteraction newViewInteraction1(); 171 run()172 public void run() { 173 i++; 174 newViewInteraction1() 175 .withFailureHandler(this::handleFailure) 176 .perform(click()); 177 Log.i(TAG, "newViewInteraction1 succeeds."); 178 } 179 handleFailure(Throwable e, Matcher<View> matcher)180 private void handleFailure(Throwable e, Matcher<View> matcher) { 181 Log.i(TAG, "espresso handleFailure count: " + i, e); 182 if (i < mRetries) { 183 SystemClock.sleep(mDelayMillis); 184 run(); 185 } else { 186 new DefaultFailureHandler(getContext()).handle(e, matcher); 187 } 188 } 189 } 190 } 191 192