• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_MANAGED_DEVICE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
21 import static android.support.test.espresso.Espresso.onView;
22 import static android.support.test.espresso.Espresso.pressBack;
23 import static android.support.test.espresso.action.ViewActions.click;
24 import static android.support.test.espresso.assertion.ViewAssertions.matches;
25 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
26 import static android.support.test.espresso.matcher.ViewMatchers.withId;
27 import static android.support.test.espresso.matcher.ViewMatchers.withText;
28 
29 import static com.android.managedprovisioning.common.LogoUtils.saveOrganisationLogo;
30 import static com.android.managedprovisioning.model.CustomizationParams.DEFAULT_COLOR_ID_DO;
31 import static com.android.managedprovisioning.model.CustomizationParams.DEFAULT_COLOR_ID_MP;
32 
33 import static org.junit.Assert.assertFalse;
34 import static org.junit.Assert.assertTrue;
35 import static org.mockito.Matchers.any;
36 import static org.mockito.Matchers.anyString;
37 import static org.mockito.Mockito.never;
38 import static org.mockito.Mockito.verify;
39 import static org.mockito.Mockito.verifyNoMoreInteractions;
40 
41 import static java.util.Arrays.asList;
42 
43 import android.app.Activity;
44 import android.content.ComponentName;
45 import android.content.Context;
46 import android.content.Intent;
47 import android.graphics.Color;
48 import android.os.Bundle;
49 import android.provider.Settings;
50 import android.support.test.InstrumentationRegistry;
51 import android.support.test.filters.SmallTest;
52 import android.support.test.rule.ActivityTestRule;
53 
54 import com.android.managedprovisioning.R;
55 import com.android.managedprovisioning.TestInstrumentationRunner;
56 import com.android.managedprovisioning.common.CustomizationVerifier;
57 import com.android.managedprovisioning.common.UriBitmap;
58 import com.android.managedprovisioning.common.Utils;
59 import com.android.managedprovisioning.model.ProvisioningParams;
60 
61 import org.junit.After;
62 import org.junit.AfterClass;
63 import org.junit.Before;
64 import org.junit.BeforeClass;
65 import org.junit.Rule;
66 import org.junit.Test;
67 import org.mockito.Mock;
68 import org.mockito.MockitoAnnotations;
69 
70 import java.io.IOException;
71 
72 /**
73  * Unit tests for {@link ProvisioningActivity}.
74  */
75 @SmallTest
76 public class ProvisioningActivityTest {
77     private static final String ADMIN_PACKAGE = "com.test.admin";
78     private static final ComponentName ADMIN = new ComponentName(ADMIN_PACKAGE, ".Receiver");
79     public static final ProvisioningParams PROFILE_OWNER_PARAMS = new ProvisioningParams.Builder()
80             .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
81             .setDeviceAdminComponentName(ADMIN)
82             .build();
83     public static final ProvisioningParams DEVICE_OWNER_PARAMS = new ProvisioningParams.Builder()
84             .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
85             .setDeviceAdminComponentName(ADMIN)
86             .build();
87     private static final Intent PROFILE_OWNER_INTENT = new Intent()
88             .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, PROFILE_OWNER_PARAMS);
89     private static final Intent DEVICE_OWNER_INTENT = new Intent()
90             .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, DEVICE_OWNER_PARAMS);
91 
92     @Rule
93     public ActivityTestRule<ProvisioningActivity> mActivityRule = new ActivityTestRule<>(
94             ProvisioningActivity.class, true /* Initial touch mode  */,
95             false /* Lazily launch activity */);
96 
97     @Mock private ProvisioningManager mProvisioningManager;
98     @Mock private Utils mUtils;
99     private static int mRotationLocked;
100 
101     @BeforeClass
setUpClass()102     public static void setUpClass() {
103         // Stop the activity from rotating in order to keep hold of the context
104         Context context = InstrumentationRegistry.getTargetContext();
105 
106         mRotationLocked = Settings.System.getInt(context.getContentResolver(),
107                 Settings.System.ACCELEROMETER_ROTATION, 0);
108         Settings.System.putInt(context.getContentResolver(),
109                 Settings.System.ACCELEROMETER_ROTATION, 0);
110     }
111 
112     @AfterClass
tearDownClass()113     public static void tearDownClass() {
114         // Reset the rotation value back to what it was before the test
115         Context context = InstrumentationRegistry.getTargetContext();
116 
117         Settings.System.putInt(context.getContentResolver(),
118                 Settings.System.ACCELEROMETER_ROTATION, mRotationLocked);
119     }
120 
121     @Before
setUp()122     public void setUp() {
123         MockitoAnnotations.initMocks(this);
124 
125         TestInstrumentationRunner.registerReplacedActivity(ProvisioningActivity.class,
126                 (classLoader, className, intent) ->
127                         new ProvisioningActivity(mProvisioningManager, mUtils));
128     }
129 
130     @After
tearDown()131     public void tearDown() {
132         TestInstrumentationRunner.unregisterReplacedActivity(ProvisioningActivity.class);
133     }
134 
135     @Test
testLaunch()136     public void testLaunch() {
137         // GIVEN the activity was launched with a profile owner intent
138         launchActivityAndWait(PROFILE_OWNER_INTENT);
139 
140         // THEN the provisioning process should be initiated
141         verify(mProvisioningManager).maybeStartProvisioning(PROFILE_OWNER_PARAMS);
142 
143         // THEN the activity should start listening for provisioning updates
144         verify(mProvisioningManager).registerListener(any(ProvisioningManagerCallback.class));
145         verifyNoMoreInteractions(mProvisioningManager);
146     }
147 
148     @Test
testColors()149     public void testColors() {
150         Context context = InstrumentationRegistry.getTargetContext();
151 
152         // default color Managed Profile (MP)
153         assertColorsCorrect(PROFILE_OWNER_INTENT, context.getColor(DEFAULT_COLOR_ID_MP));
154 
155         // default color Device Owner (DO)
156         assertColorsCorrect(DEVICE_OWNER_INTENT, context.getColor(DEFAULT_COLOR_ID_DO));
157 
158         // custom color for both cases (MP, DO)
159         int targetColor = Color.parseColor("#d40000"); // any color (except default) would do
160         for (String action : asList(ACTION_PROVISION_MANAGED_PROFILE,
161                 ACTION_PROVISION_MANAGED_DEVICE)) {
162             ProvisioningParams provisioningParams = new ProvisioningParams.Builder()
163                     .setProvisioningAction(action)
164                     .setDeviceAdminComponentName(ADMIN)
165                     .setMainColor(targetColor)
166                     .build();
167             assertColorsCorrect(new Intent().putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS,
168                     provisioningParams), targetColor);
169         }
170     }
171 
assertColorsCorrect(Intent intent, int color)172     private void assertColorsCorrect(Intent intent, int color) {
173         launchActivityAndWait(intent);
174         Activity activity = mActivityRule.getActivity();
175 
176         CustomizationVerifier customizationVerifier = new CustomizationVerifier(activity);
177         customizationVerifier.assertStatusBarColorCorrect(color);
178         customizationVerifier.assertDefaultLogoCorrect(color);
179         customizationVerifier.assertProgressBarColorCorrect(color);
180 
181         activity.finish();
182     }
183 
184     @Test
testCustomLogo()185     public void testCustomLogo() throws IOException {
186         assertCustomLogoCorrect(PROFILE_OWNER_INTENT);
187         assertCustomLogoCorrect(DEVICE_OWNER_INTENT);
188     }
189 
assertCustomLogoCorrect(Intent intent)190     private void assertCustomLogoCorrect(Intent intent) throws IOException {
191         UriBitmap targetLogo = UriBitmap.createSimpleInstance();
192         saveOrganisationLogo(InstrumentationRegistry.getTargetContext(), targetLogo.getUri());
193         launchActivityAndWait(intent);
194         ProvisioningActivity activity = mActivityRule.getActivity();
195         new CustomizationVerifier(activity).assertCustomLogoCorrect(targetLogo.getBitmap());
196         activity.finish();
197     }
198 
199     @Test
testSavedInstanceState()200     public void testSavedInstanceState() throws Throwable {
201         // GIVEN the activity was launched with a profile owner intent
202         launchActivityAndWait(PROFILE_OWNER_INTENT);
203 
204         // THEN the provisioning process should be initiated
205         verify(mProvisioningManager).maybeStartProvisioning(PROFILE_OWNER_PARAMS);
206 
207         // WHEN the activity is recreated with a saved instance state
208         mActivityRule.runOnUiThread(() -> {
209                     Bundle bundle = new Bundle();
210                     InstrumentationRegistry.getInstrumentation()
211                             .callActivityOnSaveInstanceState(mActivityRule.getActivity(), bundle);
212                     InstrumentationRegistry.getInstrumentation()
213                             .callActivityOnCreate(mActivityRule.getActivity(), bundle);
214                 });
215 
216         // THEN provisioning should not be initiated again
217         verify(mProvisioningManager).maybeStartProvisioning(PROFILE_OWNER_PARAMS);
218     }
219 
220     @Test
testPause()221     public void testPause() throws Throwable {
222         // GIVEN the activity was launched with a profile owner intent
223         launchActivityAndWait(PROFILE_OWNER_INTENT);
224 
225         // WHEN the activity is paused
226         mActivityRule.runOnUiThread(() -> {
227             InstrumentationRegistry.getInstrumentation()
228                     .callActivityOnPause(mActivityRule.getActivity());
229         });
230 
231         // THEN the listener is unregistered
232         verify(mProvisioningManager).unregisterListener(any(ProvisioningManagerCallback.class));
233     }
234 
235     @Test
testErrorNoFactoryReset()236     public void testErrorNoFactoryReset() throws Throwable {
237         // GIVEN the activity was launched with a profile owner intent
238         launchActivityAndWait(PROFILE_OWNER_INTENT);
239 
240         // WHEN an error occurred that does not require factory reset
241         final int errorMsgId = R.string.managed_provisioning_error_text;
242         mActivityRule.runOnUiThread(() -> mActivityRule.getActivity().error(R.string.cant_set_up_device, errorMsgId, false));
243 
244         // THEN the UI should show an error dialog
245         onView(withText(errorMsgId)).check(matches(isDisplayed()));
246 
247         // WHEN clicking ok
248         onView(withId(android.R.id.button1))
249                 .check(matches(withText(R.string.device_owner_error_ok)))
250                 .perform(click());
251 
252         // THEN the activity should be finishing
253         assertTrue(mActivityRule.getActivity().isFinishing());
254     }
255 
256     @Test
testErrorFactoryReset()257     public void testErrorFactoryReset() throws Throwable {
258         // GIVEN the activity was launched with a device owner intent
259         launchActivityAndWait(DEVICE_OWNER_INTENT);
260 
261         // WHEN an error occurred that does not require factory reset
262         final int errorMsgId = R.string.managed_provisioning_error_text;
263         mActivityRule.runOnUiThread(() -> mActivityRule.getActivity().error(R.string.cant_set_up_device, errorMsgId, true));
264 
265         // THEN the UI should show an error dialog
266         onView(withText(errorMsgId)).check(matches(isDisplayed()));
267 
268         // WHEN clicking the ok button that says that factory reset is required
269         onView(withId(android.R.id.button1))
270                 .check(matches(withText(R.string.reset)))
271                 .perform(click());
272 
273         // THEN factory reset should be invoked
274         verify(mUtils).sendFactoryResetBroadcast(any(Context.class), anyString());
275     }
276 
277     @Test
testCancelProfileOwner()278     public void testCancelProfileOwner() throws Throwable {
279         // GIVEN the activity was launched with a profile owner intent
280         launchActivityAndWait(PROFILE_OWNER_INTENT);
281 
282         // WHEN the user tries to cancel
283         pressBack();
284 
285         // THEN the cancel dialog should be shown
286         onView(withText(R.string.profile_owner_cancel_message)).check(matches(isDisplayed()));
287 
288         // WHEN deciding not to cancel
289         onView(withId(android.R.id.button2))
290                 .check(matches(withText(R.string.profile_owner_cancel_cancel)))
291                 .perform(click());
292 
293         // THEN the activity should not be finished
294         assertFalse(mActivityRule.getActivity().isFinishing());
295 
296         // WHEN the user tries to cancel
297         pressBack();
298 
299         // THEN the cancel dialog should be shown
300         onView(withText(R.string.profile_owner_cancel_message)).check(matches(isDisplayed()));
301 
302         // WHEN deciding to cancel
303         onView(withId(android.R.id.button1))
304                 .check(matches(withText(R.string.profile_owner_cancel_ok)))
305                 .perform(click());
306 
307         // THEN the manager should be informed
308         verify(mProvisioningManager).cancelProvisioning();
309 
310         // THEN the activity should be finished
311         assertTrue(mActivityRule.getActivity().isFinishing());
312     }
313 
314     @Test
testCancelProfileOwner_CompProvisioningWithSkipConsent()315     public void testCancelProfileOwner_CompProvisioningWithSkipConsent() throws Throwable {
316         // GIVEN launching profile intent with skipping user consent
317         ProvisioningParams params = new ProvisioningParams.Builder()
318                 .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
319                 .setDeviceAdminComponentName(ADMIN)
320                 .setSkipUserConsent(true)
321                 .build();
322         Intent intent = new Intent()
323                 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
324         launchActivityAndWait(new Intent(intent));
325 
326         // WHEN the user tries to cancel
327         mActivityRule.runOnUiThread(() -> mActivityRule.getActivity().onBackPressed());
328 
329         // THEN never unregistering ProvisioningManager
330         verify(mProvisioningManager, never()).unregisterListener(
331                 any(ProvisioningManagerCallback.class));
332     }
333 
334     @Test
testCancelProfileOwner_CompProvisioningWithoutSkipConsent()335     public void testCancelProfileOwner_CompProvisioningWithoutSkipConsent() throws Throwable {
336         // GIVEN launching profile intent without skipping user consent
337         ProvisioningParams params = new ProvisioningParams.Builder()
338                 .setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
339                 .setDeviceAdminComponentName(ADMIN)
340                 .setSkipUserConsent(false)
341                 .build();
342         Intent intent = new Intent()
343                 .putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
344         launchActivityAndWait(new Intent(intent));
345 
346         // WHEN the user tries to cancel
347         mActivityRule.runOnUiThread(() -> mActivityRule.getActivity().onBackPressed());
348 
349         // THEN unregistering ProvisioningManager
350         verify(mProvisioningManager).unregisterListener(any(ProvisioningManagerCallback.class));
351 
352         // THEN the cancel dialog should be shown
353         onView(withText(R.string.profile_owner_cancel_message)).check(matches(isDisplayed()));
354     }
355 
356     @Test
testCancelDeviceOwner()357     public void testCancelDeviceOwner() throws Throwable {
358         // GIVEN the activity was launched with a device owner intent
359         launchActivityAndWait(DEVICE_OWNER_INTENT);
360 
361         // WHEN the user tries to cancel
362         pressBack();
363 
364         // THEN the cancel dialog should be shown
365         onView(withText(R.string.stop_setup_reset_device_question)).check(matches(isDisplayed()));
366         onView(withText(R.string.this_will_reset_take_back_first_screen))
367                 .check(matches(isDisplayed()));
368 
369         // WHEN deciding not to cancel
370         onView(withId(android.R.id.button2))
371                 .check(matches(withText(R.string.device_owner_cancel_cancel)))
372                 .perform(click());
373 
374         // THEN the activity should not be finished
375         assertFalse(mActivityRule.getActivity().isFinishing());
376 
377         // WHEN the user tries to cancel
378         pressBack();
379 
380         // THEN the cancel dialog should be shown
381         onView(withText(R.string.stop_setup_reset_device_question)).check(matches(isDisplayed()));
382 
383         // WHEN deciding to cancel
384         onView(withId(android.R.id.button1))
385                 .check(matches(withText(R.string.reset)))
386                 .perform(click());
387 
388         // THEN factory reset should be invoked
389         verify(mUtils).sendFactoryResetBroadcast(any(Context.class), anyString());
390     }
391 
392     @Test
testSuccess()393     public void testSuccess() throws Throwable {
394         // GIVEN the activity was launched with a profile owner intent
395         launchActivityAndWait(PROFILE_OWNER_INTENT);
396 
397         // WHEN preFinalization is completed
398         mActivityRule.runOnUiThread(() -> mActivityRule.getActivity().preFinalizationCompleted());
399 
400         // THEN the activity should finish
401         assertTrue(mActivityRule.getActivity().isFinishing());
402     }
403 
launchActivityAndWait(Intent intent)404     private void launchActivityAndWait(Intent intent) {
405         mActivityRule.launchActivity(intent);
406         onView(withId(R.id.setup_wizard_layout));
407     }
408 }
409