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