• 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 MainClearTest {
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 MainClear mMainClear;
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         mMainClear = spy(new MainClear() {
106             @Override
107             boolean showAnySubscriptionInfo(Context context) { return true; }
108         });
109         mActivity = Robolectric.setupActivity(FragmentActivity.class);
110         mShadowActivity = Shadows.shadowOf(mActivity);
111         UserManager userManager = mActivity.getSystemService(UserManager.class);
112         mShadowUserManager = Shadows.shadowOf(userManager);
113         mShadowUserManager.setIsAdminUser(true);
114         mContentView = LayoutInflater.from(mActivity).inflate(R.layout.main_clear, null);
115 
116         // Make scrollView only have one child
117         when(mScrollView.getChildAt(0)).thenReturn(mLinearLayout);
118         when(mScrollView.getChildCount()).thenReturn(1);
119     }
120 
121     @After
tearDown()122     public void tearDown() {
123         mShadowUserManager.setIsAdminUser(false);
124     }
125 
126     @Test
testShowFinalConfirmation_eraseEsimVisible_eraseEsimChecked()127     public void testShowFinalConfirmation_eraseEsimVisible_eraseEsimChecked() {
128         final Context context = mock(Context.class);
129         when(mMainClear.getContext()).thenReturn(context);
130 
131         mMainClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
132         mMainClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
133         mMainClear.mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
134         mMainClear.mEsimStorageContainer.setVisibility(View.VISIBLE);
135         mMainClear.mEsimStorage.setChecked(true);
136         mMainClear.showFinalConfirmation();
137 
138         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
139 
140         verify(context).startActivity(intent.capture());
141         assertThat(intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
142                 .getBoolean(MainClear.ERASE_ESIMS_EXTRA, false))
143                 .isTrue();
144     }
145 
146     @Test
testShowFinalConfirmation_eraseEsimVisible_eraseEsimUnchecked()147     public void testShowFinalConfirmation_eraseEsimVisible_eraseEsimUnchecked() {
148         final Context context = mock(Context.class);
149         when(mMainClear.getContext()).thenReturn(context);
150 
151         mMainClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
152         mMainClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
153         mMainClear.mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
154         mMainClear.mEsimStorageContainer.setVisibility(View.VISIBLE);
155         mMainClear.mEsimStorage.setChecked(false);
156         mMainClear.showFinalConfirmation();
157         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
158 
159         verify(context).startActivity(intent.capture());
160         assertThat(intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
161                 .getBoolean(MainClear.ERASE_ESIMS_EXTRA, false))
162                 .isFalse();
163     }
164 
165     @Test
testShowFinalConfirmation_eraseEsimGone_eraseEsimChecked()166     public void testShowFinalConfirmation_eraseEsimGone_eraseEsimChecked() {
167         final Context context = mock(Context.class);
168         when(mMainClear.getContext()).thenReturn(context);
169 
170         mMainClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
171         mMainClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
172         mMainClear.mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
173         mMainClear.mEsimStorageContainer.setVisibility(View.GONE);
174         mMainClear.mEsimStorage.setChecked(true);
175         mMainClear.showFinalConfirmation();
176 
177         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
178 
179         verify(context).startActivity(intent.capture());
180         assertThat(intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
181             .getBoolean(MainClear.ERASE_ESIMS_EXTRA, false))
182             .isTrue();
183     }
184 
185     @Test
testShowFinalConfirmation_eraseEsimGone_eraseEsimUnchecked()186     public void testShowFinalConfirmation_eraseEsimGone_eraseEsimUnchecked() {
187         final Context context = mock(Context.class);
188         when(mMainClear.getContext()).thenReturn(context);
189 
190         mMainClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
191         mMainClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
192         mMainClear.mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
193         mMainClear.mEsimStorageContainer.setVisibility(View.GONE);
194         mMainClear.mEsimStorage.setChecked(false);
195         mMainClear.showFinalConfirmation();
196         final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
197 
198         verify(context).startActivity(intent.capture());
199         assertThat(intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
200             .getBoolean(MainClear.ERASE_ESIMS_EXTRA, false))
201             .isFalse();
202     }
203 
204     @Test
testShowWipeEuicc_euiccDisabled()205     public void testShowWipeEuicc_euiccDisabled() {
206         prepareEuiccState(
207                 false /* isEuiccEnabled */,
208                 true /* isEuiccProvisioned */,
209                 false /* isDeveloper */);
210         assertThat(mMainClear.showWipeEuicc()).isFalse();
211     }
212 
213     @Test
testShowWipeEuicc_euiccEnabled_unprovisioned()214     public void testShowWipeEuicc_euiccEnabled_unprovisioned() {
215         prepareEuiccState(
216                 true /* isEuiccEnabled */,
217                 false /* isEuiccProvisioned */,
218                 false /* isDeveloper */);
219         assertThat(mMainClear.showWipeEuicc()).isFalse();
220     }
221 
222     @Test
testShowWipeEuicc_euiccEnabled_provisioned()223     public void testShowWipeEuicc_euiccEnabled_provisioned() {
224         prepareEuiccState(
225                 true /* isEuiccEnabled */,
226                 true /* isEuiccProvisioned */,
227                 false /* isDeveloper */);
228         assertThat(mMainClear.showWipeEuicc()).isTrue();
229     }
230 
231     @Test
testShowWipeEuicc_developerMode_unprovisioned()232     public void testShowWipeEuicc_developerMode_unprovisioned() {
233         prepareEuiccState(
234                 true /* isEuiccEnabled */,
235                 false /* isEuiccProvisioned */,
236                 true /* isDeveloper */);
237         assertThat(mMainClear.showWipeEuicc()).isTrue();
238     }
239 
240     @Test
testEsimRecheckBoxDefaultChecked()241     public void testEsimRecheckBoxDefaultChecked() {
242         assertThat(((CheckBox) mContentView.findViewById(R.id.erase_esim)).isChecked()).isFalse();
243     }
244 
245     @Test
testHasReachedBottom_NotScrollDown_returnFalse()246     public void testHasReachedBottom_NotScrollDown_returnFalse() {
247         initScrollView(100, 0, 200);
248 
249         assertThat(mMainClear.hasReachedBottom(mScrollView)).isFalse();
250     }
251 
252     @Test
testHasReachedBottom_CanNotScroll_returnTrue()253     public void testHasReachedBottom_CanNotScroll_returnTrue() {
254         initScrollView(100, 0, 80);
255 
256         assertThat(mMainClear.hasReachedBottom(mScrollView)).isTrue();
257     }
258 
259     @Test
testHasReachedBottom_ScrollToBottom_returnTrue()260     public void testHasReachedBottom_ScrollToBottom_returnTrue() {
261         initScrollView(100, 100, 200);
262 
263         assertThat(mMainClear.hasReachedBottom(mScrollView)).isTrue();
264     }
265 
266     @Test
testInitiateMainClear_inDemoMode_sendsIntent()267     public void testInitiateMainClear_inDemoMode_sendsIntent() {
268         ShadowUtils.setIsDemoUser(true);
269 
270         final ComponentName componentName =
271                 ComponentName.unflattenFromString("com.android.retaildemo/.DeviceAdminReceiver");
272         ShadowUtils.setDeviceOwnerComponent(componentName);
273 
274         mMainClear.mInitiateListener.onClick(mContentView);
275         final Intent intent = mShadowActivity.getNextStartedActivity();
276         assertThat(Intent.ACTION_FACTORY_RESET).isEqualTo(intent.getAction());
277         assertThat(componentName).isNotNull();
278         assertThat(componentName.getPackageName()).isEqualTo(intent.getPackage());
279     }
280 
281     @Test
testOnActivityResultInternal_invalideRequest()282     public void testOnActivityResultInternal_invalideRequest() {
283         int invalidRequestCode = -1;
284         doReturn(false).when(mMainClear).isValidRequestCode(eq(invalidRequestCode));
285 
286         mMainClear.onActivityResultInternal(invalidRequestCode, Activity.RESULT_OK, null);
287 
288         verify(mMainClear, times(1)).isValidRequestCode(eq(invalidRequestCode));
289         verify(mMainClear, times(0)).establishInitialState();
290         verify(mMainClear, times(0)).getAccountConfirmationIntent();
291         verify(mMainClear, times(0)).showFinalConfirmation();
292     }
293 
294     @Test
testOnActivityResultInternal_resultCanceled()295     public void testOnActivityResultInternal_resultCanceled() {
296         doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
297         doNothing().when(mMainClear).establishInitialState();
298 
299         mMainClear
300                 .onActivityResultInternal(MainClear.KEYGUARD_REQUEST, Activity.RESULT_CANCELED,
301                         null);
302 
303         verify(mMainClear, times(1)).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
304         verify(mMainClear, times(1)).establishInitialState();
305         verify(mMainClear, times(0)).getAccountConfirmationIntent();
306         verify(mMainClear, times(0)).showFinalConfirmation();
307     }
308 
309     @Test
testOnActivityResultInternal_keyguardRequestTriggeringConfirmAccount()310     public void testOnActivityResultInternal_keyguardRequestTriggeringConfirmAccount() {
311         doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
312         doReturn(mMockIntent).when(mMainClear).getAccountConfirmationIntent();
313         doNothing().when(mMainClear).showAccountCredentialConfirmation(eq(mMockIntent));
314 
315         mMainClear
316                 .onActivityResultInternal(MainClear.KEYGUARD_REQUEST, Activity.RESULT_OK, null);
317 
318         verify(mMainClear, times(1)).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
319         verify(mMainClear, times(0)).establishInitialState();
320         verify(mMainClear, times(1)).getAccountConfirmationIntent();
321         verify(mMainClear, times(1)).showAccountCredentialConfirmation(eq(mMockIntent));
322     }
323 
324     @Test
testOnActivityResultInternal_keyguardRequestTriggeringShowFinal()325     public void testOnActivityResultInternal_keyguardRequestTriggeringShowFinal() {
326         doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
327         doReturn(null).when(mMainClear).getAccountConfirmationIntent();
328         doNothing().when(mMainClear).showFinalConfirmation();
329 
330         mMainClear
331                 .onActivityResultInternal(MainClear.KEYGUARD_REQUEST, Activity.RESULT_OK, null);
332 
333         verify(mMainClear, times(1)).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
334         verify(mMainClear, times(0)).establishInitialState();
335         verify(mMainClear, times(1)).getAccountConfirmationIntent();
336         verify(mMainClear, times(1)).showFinalConfirmation();
337     }
338 
339     @Test
testOnActivityResultInternal_confirmRequestTriggeringShowFinal()340     public void testOnActivityResultInternal_confirmRequestTriggeringShowFinal() {
341         doReturn(true).when(mMainClear)
342                 .isValidRequestCode(eq(MainClear.CREDENTIAL_CONFIRM_REQUEST));
343         doNothing().when(mMainClear).showFinalConfirmation();
344 
345         mMainClear.onActivityResultInternal(
346                 MainClear.CREDENTIAL_CONFIRM_REQUEST, Activity.RESULT_OK, null);
347 
348         verify(mMainClear, times(1))
349                 .isValidRequestCode(eq(MainClear.CREDENTIAL_CONFIRM_REQUEST));
350         verify(mMainClear, times(0)).establishInitialState();
351         verify(mMainClear, times(0)).getAccountConfirmationIntent();
352         verify(mMainClear, times(1)).showFinalConfirmation();
353     }
354 
355     @Test
testGetAccountConfirmationIntent_unsupported()356     public void testGetAccountConfirmationIntent_unsupported() {
357         when(mMainClear.getActivity()).thenReturn(mActivity);
358         /* Using the default resources, account confirmation shouldn't trigger */
359         assertThat(mMainClear.getAccountConfirmationIntent()).isNull();
360     }
361 
362     @Test
testGetAccountConfirmationIntent_no_relevant_accounts()363     public void testGetAccountConfirmationIntent_no_relevant_accounts() {
364         when(mMainClear.getActivity()).thenReturn(mMockActivity);
365         when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
366         when(mMockActivity.getString(R.string.account_confirmation_package))
367                 .thenReturn(TEST_CONFIRMATION_PACKAGE);
368         when(mMockActivity.getString(R.string.account_confirmation_class))
369                 .thenReturn(TEST_CONFIRMATION_CLASS);
370 
371         Account[] accounts = new Account[0];
372         when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
373         when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
374         assertThat(mMainClear.getAccountConfirmationIntent()).isNull();
375     }
376 
377     @Test
testGetAccountConfirmationIntent_unresolved()378     public void testGetAccountConfirmationIntent_unresolved() {
379         when(mMainClear.getActivity()).thenReturn(mMockActivity);
380         when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
381         when(mMockActivity.getString(R.string.account_confirmation_package))
382                 .thenReturn(TEST_CONFIRMATION_PACKAGE);
383         when(mMockActivity.getString(R.string.account_confirmation_class))
384                 .thenReturn(TEST_CONFIRMATION_CLASS);
385         Account[] accounts = new Account[]{new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE)};
386         when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
387         when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
388         // The package manager should not resolve the confirmation intent targeting the non-existent
389         // confirmation package.
390         when(mMockActivity.getPackageManager()).thenReturn(mPackageManager);
391         assertThat(mMainClear.getAccountConfirmationIntent()).isNull();
392     }
393 
394     @Test
testTryShowAccountConfirmation_ok()395     public void testTryShowAccountConfirmation_ok() {
396         when(mMainClear.getActivity()).thenReturn(mMockActivity);
397         // Only try to show account confirmation if the appropriate resource overlays are available.
398         when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
399         when(mMockActivity.getString(R.string.account_confirmation_package))
400                 .thenReturn(TEST_CONFIRMATION_PACKAGE);
401         when(mMockActivity.getString(R.string.account_confirmation_class))
402                 .thenReturn(TEST_CONFIRMATION_CLASS);
403         // Add accounts to trigger the search for a resolving intent.
404         Account[] accounts = new Account[]{new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE)};
405         when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
406         when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
407         // The package manager should not resolve the confirmation intent targeting the non-existent
408         // confirmation package.
409         when(mMockActivity.getPackageManager()).thenReturn(mPackageManager);
410 
411         ActivityInfo activityInfo = new ActivityInfo();
412         activityInfo.packageName = TEST_CONFIRMATION_PACKAGE;
413         ResolveInfo resolveInfo = new ResolveInfo();
414         resolveInfo.activityInfo = activityInfo;
415         when(mPackageManager.resolveActivity(any(), eq(0))).thenReturn(resolveInfo);
416 
417         Intent actualIntent = mMainClear.getAccountConfirmationIntent();
418         assertThat(TEST_CONFIRMATION_PACKAGE).isEqualTo(
419                 actualIntent.getComponent().getPackageName());
420         assertThat(TEST_CONFIRMATION_CLASS).isEqualTo(actualIntent.getComponent().getClassName());
421     }
422 
423     @Test
testShowAccountCredentialConfirmation()424     public void testShowAccountCredentialConfirmation() {
425         // Finally mock out the startActivityForResultCall
426         doNothing().when(mMainClear)
427                 .startActivityForResult(eq(mMockIntent),
428                         eq(MainClear.CREDENTIAL_CONFIRM_REQUEST));
429         mMainClear.showAccountCredentialConfirmation(mMockIntent);
430         verify(mMainClear, times(1))
431                 .startActivityForResult(eq(mMockIntent),
432                         eq(MainClear.CREDENTIAL_CONFIRM_REQUEST));
433     }
434 
435     @Test
testIsValidRequestCode()436     public void testIsValidRequestCode() {
437         assertThat(mMainClear.isValidRequestCode(MainClear.KEYGUARD_REQUEST)).isTrue();
438         assertThat(mMainClear.isValidRequestCode(MainClear.CREDENTIAL_CONFIRM_REQUEST))
439                 .isTrue();
440         assertThat(mMainClear.isValidRequestCode(0)).isFalse();
441     }
442 
443     @Test
testOnGlobalLayout_shouldNotRemoveListener()444     public void testOnGlobalLayout_shouldNotRemoveListener() {
445         final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
446         mMainClear.mScrollView = mScrollView;
447         doNothing().when(mMainClear).onGlobalLayout();
448         doReturn(true).when(mMainClear).hasReachedBottom(any());
449         when(mScrollView.getViewTreeObserver()).thenReturn(viewTreeObserver);
450 
451         mMainClear.onGlobalLayout();
452 
453         verify(viewTreeObserver, never()).removeOnGlobalLayoutListener(mMainClear);
454     }
455 
prepareEuiccState( boolean isEuiccEnabled, boolean isEuiccProvisioned, boolean isDeveloper)456     private void prepareEuiccState(
457             boolean isEuiccEnabled, boolean isEuiccProvisioned, boolean isDeveloper) {
458         doReturn(mActivity).when(mMainClear).getContext();
459         doReturn(isEuiccEnabled).when(mMainClear).isEuiccEnabled(any());
460         ContentResolver cr = mActivity.getContentResolver();
461         Settings.Global.putInt(cr, Settings.Global.EUICC_PROVISIONED, isEuiccProvisioned ? 1 : 0);
462         DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(mActivity, isDeveloper);
463     }
464 
initScrollView(int height, int scrollY, int childBottom)465     private void initScrollView(int height, int scrollY, int childBottom) {
466         when(mScrollView.getHeight()).thenReturn(height);
467         when(mScrollView.getScrollY()).thenReturn(scrollY);
468         when(mLinearLayout.getBottom()).thenReturn(childBottom);
469     }
470 }
471