Home | History | Annotate | Download | only in settings
      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 (at) 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
     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
    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
    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
    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
    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
    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
    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
    181     public void testEsimRecheckBoxDefaultChecked() {
    182         assertThat(((CheckBox) mContentView.findViewById(R.id.erase_esim)).isChecked()).isTrue();
    183     }
    184 
    185     @Test
    186     public void testHasReachedBottom_NotScrollDown_returnFalse() {
    187         initScrollView(100, 0, 200);
    188 
    189         assertThat(mMasterClear.hasReachedBottom(mScrollView)).isFalse();
    190     }
    191 
    192     @Test
    193     public void testHasReachedBottom_CanNotScroll_returnTrue() {
    194         initScrollView(100, 0, 80);
    195 
    196         assertThat(mMasterClear.hasReachedBottom(mScrollView)).isTrue();
    197     }
    198 
    199     @Test
    200     public void testHasReachedBottom_ScrollToBottom_returnTrue() {
    201         initScrollView(100, 100, 200);
    202 
    203         assertThat(mMasterClear.hasReachedBottom(mScrollView)).isTrue();
    204     }
    205 
    206     @Test
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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 
    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