• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package com.android.settings.accounts;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import static org.mockito.Answers.RETURNS_DEEP_STUBS;
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.anyInt;
23 import static org.mockito.ArgumentMatchers.eq;
24 import static org.mockito.ArgumentMatchers.nullable;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.accounts.Account;
31 import android.accounts.AccountManager;
32 import android.accounts.AccountManagerCallback;
33 import android.accounts.AccountManagerFuture;
34 import android.accounts.AuthenticatorDescription;
35 import android.accounts.AuthenticatorException;
36 import android.accounts.OperationCanceledException;
37 import android.app.Activity;
38 import android.content.Context;
39 import android.os.Bundle;
40 import android.os.Handler;
41 import android.os.UserHandle;
42 
43 import androidx.fragment.app.FragmentActivity;
44 import androidx.fragment.app.FragmentManager;
45 import androidx.fragment.app.FragmentTransaction;
46 import androidx.preference.PreferenceFragmentCompat;
47 import androidx.preference.PreferenceManager;
48 import androidx.preference.PreferenceScreen;
49 
50 import com.android.settings.R;
51 import com.android.settings.testutils.shadow.ShadowAccountManager;
52 import com.android.settings.testutils.shadow.ShadowContentResolver;
53 import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
54 import com.android.settings.testutils.shadow.ShadowFragment;
55 import com.android.settings.testutils.shadow.ShadowUserManager;
56 import com.android.settings.widget.RestrictedButton;
57 import com.android.settingslib.widget.LayoutPreference;
58 
59 import org.junit.After;
60 import org.junit.Before;
61 import org.junit.Test;
62 import org.junit.runner.RunWith;
63 import org.mockito.ArgumentCaptor;
64 import org.mockito.Mock;
65 import org.mockito.MockitoAnnotations;
66 import org.robolectric.Robolectric;
67 import org.robolectric.RobolectricTestRunner;
68 import org.robolectric.RuntimeEnvironment;
69 import org.robolectric.annotation.Config;
70 import org.robolectric.shadows.ShadowApplication;
71 
72 import java.io.IOException;
73 
74 @RunWith(RobolectricTestRunner.class)
75 @Config(shadows = {
76         ShadowUserManager.class,
77         ShadowDevicePolicyManager.class,
78         ShadowFragment.class,
79 })
80 public class RemoveAccountPreferenceControllerTest {
81 
82     private static final String KEY_REMOVE_ACCOUNT = "remove_account";
83     private static final String TAG_REMOVE_ACCOUNT_DIALOG = "confirmRemoveAccount";
84 
85     @Mock(answer = RETURNS_DEEP_STUBS)
86     private AccountManager mAccountManager;
87     @Mock
88     private PreferenceFragmentCompat mFragment;
89     @Mock
90     private PreferenceManager mPreferenceManager;
91     @Mock
92     private PreferenceScreen mScreen;
93     @Mock
94     private FragmentManager mFragmentManager;
95     @Mock
96     private FragmentTransaction mFragmentTransaction;
97     @Mock
98     private LayoutPreference mPreference;
99 
100     private RemoveAccountPreferenceController mController;
101 
102     @Before
setUp()103     public void setUp() {
104         MockitoAnnotations.initMocks(this);
105         ShadowApplication.getInstance().setSystemService(Context.ACCOUNT_SERVICE, mAccountManager);
106 
107         when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
108         when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
109         when(mPreferenceManager.getContext()).thenReturn(RuntimeEnvironment.application);
110         when(mFragment.getFragmentManager()).thenReturn(mFragmentManager);
111         when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
112         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt()))
113                 .thenReturn(new AuthenticatorDescription[0]);
114         when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
115         mController = new RemoveAccountPreferenceController(
116                 Robolectric.setupActivity(Activity.class), mFragment);
117     }
118 
119     @After
tearDown()120     public void tearDown() {
121         ShadowContentResolver.reset();
122     }
123 
124     @Test
displayPreference_shouldAddClickListener()125     public void displayPreference_shouldAddClickListener() {
126         when(mScreen.findPreference(KEY_REMOVE_ACCOUNT)).thenReturn(mPreference);
127         final RestrictedButton button = mock(RestrictedButton.class);
128         when(mPreference.findViewById(R.id.button)).thenReturn(button);
129 
130         mController.displayPreference(mScreen);
131 
132         verify(button).setOnClickListener(mController);
133     }
134 
135     @Test
onClick_shouldStartConfirmDialog()136     public void onClick_shouldStartConfirmDialog() {
137         when(mFragment.isAdded()).thenReturn(true);
138         mController.onClick(null);
139 
140         verify(mFragmentTransaction).add(
141                 any(RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.class),
142                 eq(TAG_REMOVE_ACCOUNT_DIALOG));
143     }
144 
145     @Test
146     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class,
147             ShadowFragment.class})
confirmRemove_shouldRemoveAccount()148     public void confirmRemove_shouldRemoveAccount()
149             throws AuthenticatorException, OperationCanceledException, IOException {
150         when(mFragment.isAdded()).thenReturn(true);
151         FragmentActivity activity = mock(FragmentActivity.class);
152         when(activity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
153         when(mFragment.getActivity()).thenReturn(activity);
154 
155         Account account = new Account("Account11", "com.acct1");
156         UserHandle userHandle = new UserHandle(10);
157         RemoveAccountPreferenceController.ConfirmRemoveAccountDialog dialog =
158                 RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.show(
159                         mFragment, account, userHandle);
160         dialog.onCreate(new Bundle());
161         dialog.onClick(null, 0);
162         ArgumentCaptor<AccountManagerCallback<Bundle>> callbackCaptor = ArgumentCaptor.forClass(
163                 AccountManagerCallback.class);
164         verify(mAccountManager).removeAccountAsUser(eq(account), nullable(Activity.class),
165                 callbackCaptor.capture(), nullable(Handler.class), eq(userHandle));
166 
167         AccountManagerCallback<Bundle> callback = callbackCaptor.getValue();
168         assertThat(callback).isNotNull();
169         AccountManagerFuture<Bundle> future = mock(AccountManagerFuture.class);
170         Bundle resultBundle = new Bundle();
171         resultBundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
172         when(future.getResult()).thenReturn(resultBundle);
173 
174         callback.run(future);
175         verify(activity).finish();
176     }
177 
178     @Test
179     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class,
180             ShadowFragment.class})
confirmRemove_activityGone_shouldSilentlyRemoveAccount()181     public void confirmRemove_activityGone_shouldSilentlyRemoveAccount()
182             throws AuthenticatorException, OperationCanceledException, IOException {
183         final Account account = new Account("Account11", "com.acct1");
184         final UserHandle userHandle = new UserHandle(10);
185         final FragmentActivity activity = mock(FragmentActivity.class);
186         when(mFragment.isAdded()).thenReturn(true);
187         when(activity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
188         when(mFragment.getActivity()).thenReturn(activity).thenReturn(null);
189 
190         final RemoveAccountPreferenceController.ConfirmRemoveAccountDialog dialog =
191                 RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.show(
192                         mFragment, account, userHandle);
193         dialog.onCreate(new Bundle());
194         dialog.onClick(null, 0);
195 
196         ArgumentCaptor<AccountManagerCallback<Bundle>> callbackCaptor = ArgumentCaptor.forClass(
197                 AccountManagerCallback.class);
198         verify(mAccountManager).removeAccountAsUser(eq(account), nullable(Activity.class),
199                 callbackCaptor.capture(), nullable(Handler.class), eq(userHandle));
200 
201         AccountManagerCallback<Bundle> callback = callbackCaptor.getValue();
202         assertThat(callback).isNotNull();
203         AccountManagerFuture<Bundle> future = mock(AccountManagerFuture.class);
204         Bundle resultBundle = new Bundle();
205         resultBundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
206         when(future.getResult()).thenReturn(resultBundle);
207 
208         callback.run(future);
209         verify(activity, never()).finish();
210     }
211 }
212