• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.settings;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.Mockito.any;
22 import static org.mockito.Mockito.doNothing;
23 import static org.mockito.Mockito.doReturn;
24 import static org.mockito.Mockito.eq;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.spy;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.when;
31 
32 import android.accounts.Account;
33 import android.accounts.AccountManager;
34 import android.app.Activity;
35 import android.content.ComponentName;
36 import android.content.ContentResolver;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.pm.ActivityInfo;
40 import android.content.pm.PackageManager;
41 import android.content.pm.ResolveInfo;
42 import android.os.UserManager;
43 import android.provider.Settings;
44 import android.view.LayoutInflater;
45 import android.view.View;
46 import android.view.ViewTreeObserver;
47 import android.widget.CheckBox;
48 import android.widget.LinearLayout;
49 import android.widget.ScrollView;
50 
51 import androidx.fragment.app.FragmentActivity;
52 
53 import com.android.settings.testutils.shadow.ShadowUtils;
54 import com.android.settingslib.development.DevelopmentSettingsEnabler;
55 
56 import org.junit.After;
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.mockito.ArgumentCaptor;
61 import org.mockito.Mock;
62 import org.mockito.MockitoAnnotations;
63 import org.robolectric.Robolectric;
64 import org.robolectric.RobolectricTestRunner;
65 import org.robolectric.Shadows;
66 import org.robolectric.annotation.Config;
67 import org.robolectric.shadows.ShadowActivity;
68 import org.robolectric.shadows.ShadowUserManager;
69 
70 @RunWith(RobolectricTestRunner.class)
71 @Config(shadows = ShadowUtils.class)
72 public class MasterClearTest {
73 
74     private static final String TEST_ACCOUNT_TYPE = "android.test.account.type";
75     private static final String TEST_CONFIRMATION_PACKAGE = "android.test.conf.pkg";
76     private static final String TEST_CONFIRMATION_CLASS = "android.test.conf.pkg.ConfActivity";
77     private static final String TEST_ACCOUNT_NAME = "test@example.com";
78 
79     @Mock
80     private ScrollView mScrollView;
81     @Mock
82     private LinearLayout mLinearLayout;
83 
84     @Mock
85     private PackageManager mPackageManager;
86 
87     @Mock
88     private AccountManager mAccountManager;
89 
90     @Mock
91     private FragmentActivity mMockActivity;
92 
93     @Mock
94     private Intent mMockIntent;
95 
96     private MasterClear mMasterClear;
97     private ShadowActivity mShadowActivity;
98     private FragmentActivity mActivity;
99     private ShadowUserManager mShadowUserManager;
100     private View mContentView;
101 
102     @Before
setUp()103     public void setUp() {
104         MockitoAnnotations.initMocks(this);
105         mMasterClear = spy(new MasterClear());
106         mActivity = Robolectric.setupActivity(FragmentActivity.class);
107         mShadowActivity = Shadows.shadowOf(mActivity);
108         UserManager userManager = mActivity.getSystemService(UserManager.class);
109         mShadowUserManager = Shadows.shadowOf(userManager);
110         mShadowUserManager.setIsAdminUser(true);
111         mContentView = LayoutInflater.from(mActivity).inflate(R.layout.master_clear, null);
112 
113         // Make scrollView only have one child
114         when(mScrollView.getChildAt(0)).thenReturn(mLinearLayout);
115         when(mScrollView.getChildCount()).thenReturn(1);
116     }
117 
118     @After
tearDown()119     public void tearDown() {
120         mShadowUserManager.setIsAdminUser(false);
121     }
122 
123     @Test
testShowFinalConfirmation_eraseEsimVisible_eraseEsimChecked()124     public void testShowFinalConfirmation_eraseEsimVisible_eraseEsimChecked() {
125         final Context context = mock(Context.class);
126         when(mMasterClear.getContext()).thenReturn(context);
127 
128         mMasterClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
129         mMasterClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
130         mMasterClear.mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
131         mMasterClear.mEsimStorageContainer.setVisibility(View.VISIBLE);
132         mMasterClear.mEsimStorage.setChecked(true);
133         mMasterClear.showFinalConfirmation();
134 
135         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
136 
137         verify(context).startActivity(intent.capture());
138         assertThat(intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
139                 .getBoolean(MasterClear.ERASE_ESIMS_EXTRA, false))
140                 .isTrue();
141     }
142 
143     @Test
testShowFinalConfirmation_eraseEsimVisible_eraseEsimUnchecked()144     public void testShowFinalConfirmation_eraseEsimVisible_eraseEsimUnchecked() {
145         final Context context = mock(Context.class);
146         when(mMasterClear.getContext()).thenReturn(context);
147 
148         mMasterClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
149         mMasterClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
150         mMasterClear.mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
151         mMasterClear.mEsimStorageContainer.setVisibility(View.VISIBLE);
152         mMasterClear.mEsimStorage.setChecked(false);
153         mMasterClear.showFinalConfirmation();
154         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
155 
156         verify(context).startActivity(intent.capture());
157         assertThat(intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
158                 .getBoolean(MasterClear.ERASE_ESIMS_EXTRA, false))
159                 .isFalse();
160     }
161 
162     @Test
testShowFinalConfirmation_eraseEsimGone_eraseEsimChecked()163     public void testShowFinalConfirmation_eraseEsimGone_eraseEsimChecked() {
164         final Context context = mock(Context.class);
165         when(mMasterClear.getContext()).thenReturn(context);
166 
167         mMasterClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
168         mMasterClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
169         mMasterClear.mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
170         mMasterClear.mEsimStorageContainer.setVisibility(View.GONE);
171         mMasterClear.mEsimStorage.setChecked(true);
172         mMasterClear.showFinalConfirmation();
173 
174         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
175 
176         verify(context).startActivity(intent.capture());
177         assertThat(intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
178             .getBoolean(MasterClear.ERASE_ESIMS_EXTRA, false))
179             .isTrue();
180     }
181 
182     @Test
testShowFinalConfirmation_eraseEsimGone_eraseEsimUnchecked()183     public void testShowFinalConfirmation_eraseEsimGone_eraseEsimUnchecked() {
184         final Context context = mock(Context.class);
185         when(mMasterClear.getContext()).thenReturn(context);
186 
187         mMasterClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
188         mMasterClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
189         mMasterClear.mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
190         mMasterClear.mEsimStorageContainer.setVisibility(View.GONE);
191         mMasterClear.mEsimStorage.setChecked(false);
192         mMasterClear.showFinalConfirmation();
193         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
194 
195         verify(context).startActivity(intent.capture());
196         assertThat(intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
197             .getBoolean(MasterClear.ERASE_ESIMS_EXTRA, false))
198             .isFalse();
199     }
200 
201     @Test
testShowWipeEuicc_euiccDisabled()202     public void testShowWipeEuicc_euiccDisabled() {
203         prepareEuiccState(
204                 false /* isEuiccEnabled */,
205                 true /* isEuiccProvisioned */,
206                 false /* isDeveloper */);
207         assertThat(mMasterClear.showWipeEuicc()).isFalse();
208     }
209 
210     @Test
testShowWipeEuicc_euiccEnabled_unprovisioned()211     public void testShowWipeEuicc_euiccEnabled_unprovisioned() {
212         prepareEuiccState(
213                 true /* isEuiccEnabled */,
214                 false /* isEuiccProvisioned */,
215                 false /* isDeveloper */);
216         assertThat(mMasterClear.showWipeEuicc()).isFalse();
217     }
218 
219     @Test
testShowWipeEuicc_euiccEnabled_provisioned()220     public void testShowWipeEuicc_euiccEnabled_provisioned() {
221         prepareEuiccState(
222                 true /* isEuiccEnabled */,
223                 true /* isEuiccProvisioned */,
224                 false /* isDeveloper */);
225         assertThat(mMasterClear.showWipeEuicc()).isTrue();
226     }
227 
228     @Test
testShowWipeEuicc_developerMode_unprovisioned()229     public void testShowWipeEuicc_developerMode_unprovisioned() {
230         prepareEuiccState(
231                 true /* isEuiccEnabled */,
232                 false /* isEuiccProvisioned */,
233                 true /* isDeveloper */);
234         assertThat(mMasterClear.showWipeEuicc()).isTrue();
235     }
236 
237     @Test
testEsimRecheckBoxDefaultChecked()238     public void testEsimRecheckBoxDefaultChecked() {
239         assertThat(((CheckBox) mContentView.findViewById(R.id.erase_esim)).isChecked()).isTrue();
240     }
241 
242     @Test
testHasReachedBottom_NotScrollDown_returnFalse()243     public void testHasReachedBottom_NotScrollDown_returnFalse() {
244         initScrollView(100, 0, 200);
245 
246         assertThat(mMasterClear.hasReachedBottom(mScrollView)).isFalse();
247     }
248 
249     @Test
testHasReachedBottom_CanNotScroll_returnTrue()250     public void testHasReachedBottom_CanNotScroll_returnTrue() {
251         initScrollView(100, 0, 80);
252 
253         assertThat(mMasterClear.hasReachedBottom(mScrollView)).isTrue();
254     }
255 
256     @Test
testHasReachedBottom_ScrollToBottom_returnTrue()257     public void testHasReachedBottom_ScrollToBottom_returnTrue() {
258         initScrollView(100, 100, 200);
259 
260         assertThat(mMasterClear.hasReachedBottom(mScrollView)).isTrue();
261     }
262 
263     @Test
testInitiateMasterClear_inDemoMode_sendsIntent()264     public void testInitiateMasterClear_inDemoMode_sendsIntent() {
265         ShadowUtils.setIsDemoUser(true);
266 
267         final ComponentName componentName =
268                 ComponentName.unflattenFromString("com.android.retaildemo/.DeviceAdminReceiver");
269         ShadowUtils.setDeviceOwnerComponent(componentName);
270 
271         mMasterClear.mInitiateListener.onClick(mContentView);
272         final Intent intent = mShadowActivity.getNextStartedActivity();
273         assertThat(Intent.ACTION_FACTORY_RESET).isEqualTo(intent.getAction());
274         assertThat(componentName).isNotNull();
275         assertThat(componentName.getPackageName()).isEqualTo(intent.getPackage());
276     }
277 
278     @Test
testOnActivityResultInternal_invalideRequest()279     public void testOnActivityResultInternal_invalideRequest() {
280         int invalidRequestCode = -1;
281         doReturn(false).when(mMasterClear).isValidRequestCode(eq(invalidRequestCode));
282 
283         mMasterClear.onActivityResultInternal(invalidRequestCode, Activity.RESULT_OK, null);
284 
285         verify(mMasterClear, times(1)).isValidRequestCode(eq(invalidRequestCode));
286         verify(mMasterClear, times(0)).establishInitialState();
287         verify(mMasterClear, times(0)).getAccountConfirmationIntent();
288         verify(mMasterClear, times(0)).showFinalConfirmation();
289     }
290 
291     @Test
testOnActivityResultInternal_resultCanceled()292     public void testOnActivityResultInternal_resultCanceled() {
293         doReturn(true).when(mMasterClear).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST));
294         doNothing().when(mMasterClear).establishInitialState();
295 
296         mMasterClear
297                 .onActivityResultInternal(MasterClear.KEYGUARD_REQUEST, Activity.RESULT_CANCELED,
298                         null);
299 
300         verify(mMasterClear, times(1)).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST));
301         verify(mMasterClear, times(1)).establishInitialState();
302         verify(mMasterClear, times(0)).getAccountConfirmationIntent();
303         verify(mMasterClear, times(0)).showFinalConfirmation();
304     }
305 
306     @Test
testOnActivityResultInternal_keyguardRequestTriggeringConfirmAccount()307     public void testOnActivityResultInternal_keyguardRequestTriggeringConfirmAccount() {
308         doReturn(true).when(mMasterClear).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST));
309         doReturn(mMockIntent).when(mMasterClear).getAccountConfirmationIntent();
310         doNothing().when(mMasterClear).showAccountCredentialConfirmation(eq(mMockIntent));
311 
312         mMasterClear
313                 .onActivityResultInternal(MasterClear.KEYGUARD_REQUEST, Activity.RESULT_OK, null);
314 
315         verify(mMasterClear, times(1)).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST));
316         verify(mMasterClear, times(0)).establishInitialState();
317         verify(mMasterClear, times(1)).getAccountConfirmationIntent();
318         verify(mMasterClear, times(1)).showAccountCredentialConfirmation(eq(mMockIntent));
319     }
320 
321     @Test
testOnActivityResultInternal_keyguardRequestTriggeringShowFinal()322     public void testOnActivityResultInternal_keyguardRequestTriggeringShowFinal() {
323         doReturn(true).when(mMasterClear).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST));
324         doReturn(null).when(mMasterClear).getAccountConfirmationIntent();
325         doNothing().when(mMasterClear).showFinalConfirmation();
326 
327         mMasterClear
328                 .onActivityResultInternal(MasterClear.KEYGUARD_REQUEST, Activity.RESULT_OK, null);
329 
330         verify(mMasterClear, times(1)).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST));
331         verify(mMasterClear, times(0)).establishInitialState();
332         verify(mMasterClear, times(1)).getAccountConfirmationIntent();
333         verify(mMasterClear, times(1)).showFinalConfirmation();
334     }
335 
336     @Test
testOnActivityResultInternal_confirmRequestTriggeringShowFinal()337     public void testOnActivityResultInternal_confirmRequestTriggeringShowFinal() {
338         doReturn(true).when(mMasterClear)
339                 .isValidRequestCode(eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST));
340         doNothing().when(mMasterClear).showFinalConfirmation();
341 
342         mMasterClear.onActivityResultInternal(
343                 MasterClear.CREDENTIAL_CONFIRM_REQUEST, Activity.RESULT_OK, null);
344 
345         verify(mMasterClear, times(1))
346                 .isValidRequestCode(eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST));
347         verify(mMasterClear, times(0)).establishInitialState();
348         verify(mMasterClear, times(0)).getAccountConfirmationIntent();
349         verify(mMasterClear, times(1)).showFinalConfirmation();
350     }
351 
352     @Test
testGetAccountConfirmationIntent_unsupported()353     public void testGetAccountConfirmationIntent_unsupported() {
354         when(mMasterClear.getActivity()).thenReturn(mActivity);
355         /* Using the default resources, account confirmation shouldn't trigger */
356         assertThat(mMasterClear.getAccountConfirmationIntent()).isNull();
357     }
358 
359     @Test
testGetAccountConfirmationIntent_no_relevant_accounts()360     public void testGetAccountConfirmationIntent_no_relevant_accounts() {
361         when(mMasterClear.getActivity()).thenReturn(mMockActivity);
362         when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
363         when(mMockActivity.getString(R.string.account_confirmation_package))
364                 .thenReturn(TEST_CONFIRMATION_PACKAGE);
365         when(mMockActivity.getString(R.string.account_confirmation_class))
366                 .thenReturn(TEST_CONFIRMATION_CLASS);
367 
368         Account[] accounts = new Account[0];
369         when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
370         when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
371         assertThat(mMasterClear.getAccountConfirmationIntent()).isNull();
372     }
373 
374     @Test
testGetAccountConfirmationIntent_unresolved()375     public void testGetAccountConfirmationIntent_unresolved() {
376         when(mMasterClear.getActivity()).thenReturn(mMockActivity);
377         when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
378         when(mMockActivity.getString(R.string.account_confirmation_package))
379                 .thenReturn(TEST_CONFIRMATION_PACKAGE);
380         when(mMockActivity.getString(R.string.account_confirmation_class))
381                 .thenReturn(TEST_CONFIRMATION_CLASS);
382         Account[] accounts = new Account[]{new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE)};
383         when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
384         when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
385         // The package manager should not resolve the confirmation intent targeting the non-existent
386         // confirmation package.
387         when(mMockActivity.getPackageManager()).thenReturn(mPackageManager);
388         assertThat(mMasterClear.getAccountConfirmationIntent()).isNull();
389     }
390 
391     @Test
testTryShowAccountConfirmation_ok()392     public void testTryShowAccountConfirmation_ok() {
393         when(mMasterClear.getActivity()).thenReturn(mMockActivity);
394         // Only try to show account confirmation if the appropriate resource overlays are available.
395         when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
396         when(mMockActivity.getString(R.string.account_confirmation_package))
397                 .thenReturn(TEST_CONFIRMATION_PACKAGE);
398         when(mMockActivity.getString(R.string.account_confirmation_class))
399                 .thenReturn(TEST_CONFIRMATION_CLASS);
400         // Add accounts to trigger the search for a resolving intent.
401         Account[] accounts = new Account[]{new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE)};
402         when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
403         when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
404         // The package manager should not resolve the confirmation intent targeting the non-existent
405         // confirmation package.
406         when(mMockActivity.getPackageManager()).thenReturn(mPackageManager);
407 
408         ActivityInfo activityInfo = new ActivityInfo();
409         activityInfo.packageName = TEST_CONFIRMATION_PACKAGE;
410         ResolveInfo resolveInfo = new ResolveInfo();
411         resolveInfo.activityInfo = activityInfo;
412         when(mPackageManager.resolveActivity(any(), eq(0))).thenReturn(resolveInfo);
413 
414         Intent actualIntent = mMasterClear.getAccountConfirmationIntent();
415         assertThat(TEST_CONFIRMATION_PACKAGE).isEqualTo(
416                 actualIntent.getComponent().getPackageName());
417         assertThat(TEST_CONFIRMATION_CLASS).isEqualTo(actualIntent.getComponent().getClassName());
418     }
419 
420     @Test
testShowAccountCredentialConfirmation()421     public void testShowAccountCredentialConfirmation() {
422         // Finally mock out the startActivityForResultCall
423         doNothing().when(mMasterClear)
424                 .startActivityForResult(eq(mMockIntent),
425                         eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST));
426         mMasterClear.showAccountCredentialConfirmation(mMockIntent);
427         verify(mMasterClear, times(1))
428                 .startActivityForResult(eq(mMockIntent),
429                         eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST));
430     }
431 
432     @Test
testIsValidRequestCode()433     public void testIsValidRequestCode() {
434         assertThat(mMasterClear.isValidRequestCode(MasterClear.KEYGUARD_REQUEST)).isTrue();
435         assertThat(mMasterClear.isValidRequestCode(MasterClear.CREDENTIAL_CONFIRM_REQUEST))
436                 .isTrue();
437         assertThat(mMasterClear.isValidRequestCode(0)).isFalse();
438     }
439 
440     @Test
testOnGlobalLayout_shouldNotRemoveListener()441     public void testOnGlobalLayout_shouldNotRemoveListener() {
442         final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
443         mMasterClear.mScrollView = mScrollView;
444         doNothing().when(mMasterClear).onGlobalLayout();
445         doReturn(true).when(mMasterClear).hasReachedBottom(any());
446         when(mScrollView.getViewTreeObserver()).thenReturn(viewTreeObserver);
447 
448         mMasterClear.onGlobalLayout();
449 
450         verify(viewTreeObserver, never()).removeOnGlobalLayoutListener(mMasterClear);
451     }
452 
prepareEuiccState( boolean isEuiccEnabled, boolean isEuiccProvisioned, boolean isDeveloper)453     private void prepareEuiccState(
454             boolean isEuiccEnabled, boolean isEuiccProvisioned, boolean isDeveloper) {
455         doReturn(mActivity).when(mMasterClear).getContext();
456         doReturn(isEuiccEnabled).when(mMasterClear).isEuiccEnabled(any());
457         ContentResolver cr = mActivity.getContentResolver();
458         Settings.Global.putInt(cr, Settings.Global.EUICC_PROVISIONED, isEuiccProvisioned ? 1 : 0);
459         DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(mActivity, isDeveloper);
460     }
461 
initScrollView(int height, int scrollY, int childBottom)462     private void initScrollView(int height, int scrollY, int childBottom) {
463         when(mScrollView.getHeight()).thenReturn(height);
464         when(mScrollView.getScrollY()).thenReturn(scrollY);
465         when(mLinearLayout.getBottom()).thenReturn(childBottom);
466     }
467 }
468