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