1 /*
2  * Copyright (C) 2019 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.car.settings.inputmethod;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26 
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ServiceInfo;
31 import android.view.inputmethod.InputMethodInfo;
32 import android.view.inputmethod.InputMethodManager;
33 import android.view.inputmethod.InputMethodSubtype;
34 
35 import androidx.lifecycle.Lifecycle;
36 import androidx.preference.Preference;
37 import androidx.preference.PreferenceGroup;
38 import androidx.preference.SwitchPreference;
39 
40 import com.android.car.settings.CarSettingsRobolectricTestRunner;
41 import com.android.car.settings.common.ConfirmationDialogFragment;
42 import com.android.car.settings.common.LogicalPreferenceGroup;
43 import com.android.car.settings.common.PreferenceControllerTestHelper;
44 import com.android.car.settings.testutils.ShadowDevicePolicyManager;
45 import com.android.car.settings.testutils.ShadowInputMethodManager;
46 
47 import org.junit.Before;
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 import org.mockito.ArgumentCaptor;
51 import org.robolectric.RuntimeEnvironment;
52 import org.robolectric.annotation.Config;
53 import org.robolectric.shadow.api.Shadow;
54 
55 import java.util.ArrayList;
56 import java.util.Arrays;
57 import java.util.List;
58 
59 @RunWith(CarSettingsRobolectricTestRunner.class)
60 @Config(shadows = {ShadowInputMethodManager.class, ShadowDevicePolicyManager.class})
61 public class KeyboardManagementPreferenceControllerTest {
62     private static final String DUMMY_LABEL = "dummy label";
63     private static final String DUMMY_SETTINGS_ACTIVITY = "dummy settings activity";
64     private static final String DUMMY_PACKAGE_NAME = "dummy package name";
65     private static final String DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE =
66             "dummy id defaultable direct boot aware";
67     private static final String DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE =
68             "dummy id defaultable not direct boot aware";
69     private static final String DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE =
70             "dummy id not defaultable direct boot aware";
71     private static final String DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE =
72             "dummy id not defaultable not direct boot aware";
73     private static final String DISALLOWED_PACKAGE_NAME = "disallowed package name";
74     private static final String ALLOWED_PACKAGE_NAME = "allowed package name";
75     private List<String> mPermittedList;
76     private PreferenceControllerTestHelper<KeyboardManagementPreferenceController>
77             mControllerHelper;
78     private PreferenceGroup mPreferenceGroup;
79     private Context mContext;
80     private InputMethodManager mInputMethodManager;
81 
82     @Before
setUp()83     public void setUp() {
84         mContext = RuntimeEnvironment.application;
85 
86         mPreferenceGroup = new LogicalPreferenceGroup(mContext);
87         mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
88                 KeyboardManagementPreferenceController.class, mPreferenceGroup);
89         mInputMethodManager = (InputMethodManager) mContext.getSystemService(Context
90                 .INPUT_METHOD_SERVICE);
91 
92         mPermittedList = new ArrayList<>();
93         mPermittedList.add(DUMMY_PACKAGE_NAME);
94         mPermittedList.add(ALLOWED_PACKAGE_NAME);
95 
96         getShadowInputMethodManager(mContext).setInputMethodList(new ArrayList<>());
97 
98         mControllerHelper.markState(Lifecycle.State.CREATED);
99     }
100 
101     @Test
refreshUi_permitAllInputMethods_preferenceCountIs4()102     public void refreshUi_permitAllInputMethods_preferenceCountIs4() {
103         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
104         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
105                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
106                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
107                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
108         getShadowInputMethodManager(mContext).setInputMethodList(infos);
109         getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
110 
111         mControllerHelper.getController().refreshUi();
112 
113         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(4);
114     }
115 
116     @Test
refreshUi_multiplteAllowedImeByOrganization_allPreferencesVisible()117     public void refreshUi_multiplteAllowedImeByOrganization_allPreferencesVisible() {
118         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(
119                 mPermittedList);
120         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
121                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
122                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
123                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
124         getShadowInputMethodManager(mContext).setInputMethodList(infos);
125         getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
126 
127         mControllerHelper.getController().refreshUi();
128 
129         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
130             assertThat(mPreferenceGroup.getPreference(i).isVisible()).isTrue();
131         }
132     }
133 
134     @Test
refreshUi_multipleEnabledInputMethods_allPreferencesEnabled()135     public void refreshUi_multipleEnabledInputMethods_allPreferencesEnabled() {
136         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(
137                 mPermittedList);
138         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
139                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
140                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
141                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
142         getShadowInputMethodManager(mContext).setInputMethodList(infos);
143         getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
144 
145         mControllerHelper.getController().refreshUi();
146 
147         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
148             assertThat(mPreferenceGroup.getPreference(i).isEnabled()).isTrue();
149         }
150     }
151 
152     @Test
refreshUi_multipleEnabledInputMethods_allPreferencesChecked()153     public void refreshUi_multipleEnabledInputMethods_allPreferencesChecked() {
154         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(
155                 mPermittedList);
156         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
157                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
158                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
159                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
160         getShadowInputMethodManager(mContext).setInputMethodList(infos);
161         getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
162 
163         mControllerHelper.getController().refreshUi();
164 
165         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
166             assertThat(((SwitchPreference) mPreferenceGroup.getPreference(i)).isChecked())
167                     .isTrue();
168         }
169     }
170 
171     @Test
refreshUi_disallowedByOrganization_noPreferencesShown()172     public void refreshUi_disallowedByOrganization_noPreferencesShown() {
173         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(
174                 mPermittedList);
175         List<InputMethodInfo> infos = createInputMethodInfoList(DISALLOWED_PACKAGE_NAME,
176                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
177                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
178                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
179         getShadowInputMethodManager(mContext).setInputMethodList(infos);
180         getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
181 
182         mControllerHelper.getController().refreshUi();
183 
184         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
185     }
186 
187     @Test
refreshUi_skipVoiceTyping()188     public void refreshUi_skipVoiceTyping() {
189         List<InputMethodInfo> infos =
190                 createInputMethodInfoList(InputMethodUtil.GOOGLE_VOICE_TYPING);
191         getShadowInputMethodManager(mContext).setInputMethodList(infos);
192 
193         mControllerHelper.getController().refreshUi();
194 
195         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
196     }
197 
198     @Test
refreshUi_verifyPreferenceIcon()199     public void refreshUi_verifyPreferenceIcon() {
200         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
201         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
202                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
203                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
204                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
205         getShadowInputMethodManager(mContext).setInputMethodList(infos);
206         getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
207 
208         mControllerHelper.getController().refreshUi();
209 
210         Preference preference = mPreferenceGroup.getPreference(0);
211         assertThat(preference.getIcon()).isEqualTo(
212                 InputMethodUtil.getPackageIcon(mContext.getPackageManager(), infos.get(0)));
213     }
214 
215     @Test
refreshUi_verifyPreferenceTitle()216     public void refreshUi_verifyPreferenceTitle() {
217         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
218         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
219                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
220                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
221                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
222         getShadowInputMethodManager(mContext).setInputMethodList(infos);
223         getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
224 
225         mControllerHelper.getController().refreshUi();
226 
227         Preference preference = mPreferenceGroup.getPreference(0);
228         assertThat(preference.getTitle()).isEqualTo(
229                 InputMethodUtil.getPackageLabel(mContext.getPackageManager(), infos.get(0)));
230     }
231 
232     @Test
refreshUi_verifyPreferenceSummary()233     public void refreshUi_verifyPreferenceSummary() {
234         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
235         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
236                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
237                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
238                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
239         getShadowInputMethodManager(mContext).setInputMethodList(infos);
240         getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
241 
242         mControllerHelper.getController().refreshUi();
243 
244         InputMethodManager inputMethodManager =
245                 (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
246         Preference preference = mPreferenceGroup.getPreference(0);
247         assertThat(preference.getSummary()).isEqualTo(
248                 InputMethodUtil.getSummaryString(mContext, inputMethodManager, infos.get(0)));
249     }
250 
251     @Test
refreshUi_oneInputMethod_noneEnabled_oneInputMethodPreferenceInView()252     public void refreshUi_oneInputMethod_noneEnabled_oneInputMethodPreferenceInView() {
253         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
254         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
255                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
256         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
257 
258         mControllerHelper.getController().refreshUi();
259 
260         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
261     }
262 
263     @Test
refreshUi_oneInputMethod_noneEnabled_preferenceEnabled()264     public void refreshUi_oneInputMethod_noneEnabled_preferenceEnabled() {
265         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
266         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
267                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
268         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
269 
270         mControllerHelper.getController().refreshUi();
271 
272         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
273     }
274 
275     @Test
refreshUi_oneInputMethod_noneEnabled_preferenceNotChecked()276     public void refreshUi_oneInputMethod_noneEnabled_preferenceNotChecked() {
277         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
278         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
279                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
280         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
281 
282         mControllerHelper.getController().refreshUi();
283 
284         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
285                 .isFalse();
286     }
287 
288     @Test
performClick_toggleTrue_securityDialogShown()289     public void performClick_toggleTrue_securityDialogShown() {
290         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
291         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
292                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
293         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
294 
295         mControllerHelper.getController().refreshUi();
296 
297         mPreferenceGroup.getPreference(0).performClick();
298 
299         verify(mControllerHelper.getMockFragmentController()).showDialog(
300                 any(ConfirmationDialogFragment.class),
301                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
302     }
303 
304     @Test
performClick_toggleTrue_showSecurityDialog_positive_noOtherPreferenceAdded()305     public void performClick_toggleTrue_showSecurityDialog_positive_noOtherPreferenceAdded() {
306         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
307         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
308                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
309         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
310 
311         mControllerHelper.getController().refreshUi();
312 
313         mPreferenceGroup.getPreference(0).performClick();
314 
315         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
316                 ConfirmationDialogFragment.class);
317         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
318                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
319         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
320 
321         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
322 
323         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
324         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
325                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
326     }
327 
328     @Test
performClick_toggleTrue_showSecurityDialog_positive_preferenceChecked()329     public void performClick_toggleTrue_showSecurityDialog_positive_preferenceChecked() {
330         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
331         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
332                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
333         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
334 
335         mControllerHelper.getController().refreshUi();
336 
337         mPreferenceGroup.getPreference(0).performClick();
338 
339         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
340                 ConfirmationDialogFragment.class);
341         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
342                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
343         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
344 
345         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
346 
347         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
348                 .isTrue();
349     }
350 
351     @Test
performClick_toggleTrue_showSecurityDialog_positive_preferenceEnabled()352     public void performClick_toggleTrue_showSecurityDialog_positive_preferenceEnabled() {
353         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
354         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
355                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
356         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
357 
358         mControllerHelper.getController().refreshUi();
359 
360         mPreferenceGroup.getPreference(0).performClick();
361 
362         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
363                 ConfirmationDialogFragment.class);
364         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
365                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
366         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
367 
368         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
369 
370         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
371     }
372 
373     @Test
performClick_toggleTrue_showSecurityDialog_positive_inputMethodEnabled()374     public void performClick_toggleTrue_showSecurityDialog_positive_inputMethodEnabled() {
375         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
376         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
377                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
378         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
379 
380         mControllerHelper.getController().refreshUi();
381 
382         mPreferenceGroup.getPreference(0).performClick();
383 
384         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
385                 ConfirmationDialogFragment.class);
386         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
387                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
388         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
389 
390         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
391 
392         assertThat(mInputMethodManager.getEnabledInputMethodList().get(0).getId())
393                 .isEqualTo(DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
394     }
395 
396     @Test
performClick_toggleTrue_showSecurityDialog_negative_noOtherPreferenceAdded()397     public void performClick_toggleTrue_showSecurityDialog_negative_noOtherPreferenceAdded() {
398         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
399         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
400                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
401         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
402 
403         mControllerHelper.getController().refreshUi();
404 
405         mPreferenceGroup.getPreference(0).performClick();
406 
407         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
408                 ConfirmationDialogFragment.class);
409         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
410                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
411         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
412 
413         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
414 
415         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
416         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
417                 DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
418     }
419 
420     @Test
performClick_toggleTrue_showSecurityDialog_negative_preferenceEnabled()421     public void performClick_toggleTrue_showSecurityDialog_negative_preferenceEnabled() {
422         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
423         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
424                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
425         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
426 
427         mControllerHelper.getController().refreshUi();
428 
429         mPreferenceGroup.getPreference(0).performClick();
430 
431         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
432                 ConfirmationDialogFragment.class);
433         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
434                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
435         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
436 
437         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
438 
439         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
440     }
441 
442     @Test
performClick_toggleTrue_showSecurityDialog_negative_inputMethodDisabled()443     public void performClick_toggleTrue_showSecurityDialog_negative_inputMethodDisabled() {
444         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
445         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
446                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
447         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
448 
449         mControllerHelper.getController().refreshUi();
450 
451         mPreferenceGroup.getPreference(0).performClick();
452 
453         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
454                 ConfirmationDialogFragment.class);
455         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
456                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
457         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
458 
459         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
460 
461         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
462                 .isFalse();
463     }
464 
465     @Test
performClick_toggleTrue_directBootWarningShown()466     public void performClick_toggleTrue_directBootWarningShown() {
467         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
468         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
469                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
470         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
471 
472         mControllerHelper.getController().refreshUi();
473 
474         mPreferenceGroup.getPreference(0).performClick();
475 
476         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
477                 ConfirmationDialogFragment.class);
478         verify(mControllerHelper.getMockFragmentController()).showDialog(
479                 securityDialogCaptor.capture(),
480                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
481         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
482 
483         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
484 
485 
486         verify(mControllerHelper.getMockFragmentController()).showDialog(
487                 any(ConfirmationDialogFragment.class),
488                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
489     }
490 
491     @Test
performClick_toggleTrue_showDirectBootDialog_positive_noOtherPreferenceAdded()492     public void performClick_toggleTrue_showDirectBootDialog_positive_noOtherPreferenceAdded() {
493         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
494         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
495                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
496         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
497 
498         mControllerHelper.getController().refreshUi();
499 
500         mPreferenceGroup.getPreference(0).performClick();
501 
502         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
503                 ConfirmationDialogFragment.class);
504         verify(mControllerHelper.getMockFragmentController()).showDialog(
505                 securityDialogCaptor.capture(),
506                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
507         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
508 
509         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
510 
511         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
512                 ConfirmationDialogFragment.class);
513         verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
514                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
515         dialogFragment = bootDialogCaptor.getValue();
516 
517         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
518 
519         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
520         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
521                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
522     }
523 
524     @Test
performClick_toggleTrue_showDirectBootDialog_positive_preferenceChecked()525     public void performClick_toggleTrue_showDirectBootDialog_positive_preferenceChecked() {
526         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
527         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
528                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
529         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
530 
531         mControllerHelper.getController().refreshUi();
532 
533         mPreferenceGroup.getPreference(0).performClick();
534 
535         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
536                 ConfirmationDialogFragment.class);
537         verify(mControllerHelper.getMockFragmentController()).showDialog(
538                 securityDialogCaptor.capture(),
539                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
540         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
541 
542         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
543 
544         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
545                 ConfirmationDialogFragment.class);
546         verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
547                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
548         dialogFragment = bootDialogCaptor.getValue();
549 
550         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
551 
552         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
553                 .isTrue();
554     }
555 
556     @Test
performClick_toggleTrue_showDirectBootDialog_positive_preferenceEnabled()557     public void performClick_toggleTrue_showDirectBootDialog_positive_preferenceEnabled() {
558         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
559         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
560                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
561         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
562 
563         mControllerHelper.getController().refreshUi();
564 
565         mPreferenceGroup.getPreference(0).performClick();
566 
567         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
568                 ConfirmationDialogFragment.class);
569         verify(mControllerHelper.getMockFragmentController()).showDialog(
570                 securityDialogCaptor.capture(),
571                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
572         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
573 
574         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
575 
576         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
577                 ConfirmationDialogFragment.class);
578         verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
579                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
580         dialogFragment = bootDialogCaptor.getValue();
581 
582         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
583 
584         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
585     }
586 
587     @Test
performClick_toggleTrue_showDirectBootDialog_positive_inputMethodEnabled()588     public void performClick_toggleTrue_showDirectBootDialog_positive_inputMethodEnabled() {
589         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
590         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
591                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
592         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
593 
594         mControllerHelper.getController().refreshUi();
595 
596         mPreferenceGroup.getPreference(0).performClick();
597 
598         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
599                 ConfirmationDialogFragment.class);
600         verify(mControllerHelper.getMockFragmentController()).showDialog(
601                 securityDialogCaptor.capture(),
602                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
603         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
604 
605         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
606 
607         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
608                 ConfirmationDialogFragment.class);
609         verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
610                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
611         dialogFragment = bootDialogCaptor.getValue();
612 
613         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
614 
615         assertThat(mInputMethodManager.getEnabledInputMethodList().get(0).getId())
616                 .isEqualTo(DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
617     }
618 
619     @Test
performClick_toggleTrue_showDirectBootDialog_negative_noOtherPreferenceAdded()620     public void performClick_toggleTrue_showDirectBootDialog_negative_noOtherPreferenceAdded() {
621         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
622         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
623                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
624         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
625 
626         mControllerHelper.getController().refreshUi();
627 
628         mPreferenceGroup.getPreference(0).performClick();
629 
630         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
631                 ConfirmationDialogFragment.class);
632         verify(mControllerHelper.getMockFragmentController()).showDialog(
633                 securityDialogCaptor.capture(),
634                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
635         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
636 
637         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
638 
639         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
640                 ConfirmationDialogFragment.class);
641         verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
642                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
643         dialogFragment = bootDialogCaptor.getValue();
644 
645         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
646 
647 
648         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
649         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
650                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
651     }
652 
653     @Test
performClick_toggleTrue_showDirectBootDialog_negative_preferenceNotChecked()654     public void performClick_toggleTrue_showDirectBootDialog_negative_preferenceNotChecked() {
655         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
656         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
657                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
658         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
659 
660         mControllerHelper.getController().refreshUi();
661 
662         mPreferenceGroup.getPreference(0).performClick();
663 
664         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
665                 ConfirmationDialogFragment.class);
666         verify(mControllerHelper.getMockFragmentController()).showDialog(
667                 securityDialogCaptor.capture(),
668                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
669         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
670 
671         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
672 
673         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
674                 ConfirmationDialogFragment.class);
675         verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
676                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
677         dialogFragment = bootDialogCaptor.getValue();
678 
679         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
680 
681 
682         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
683                 .isFalse();
684     }
685 
686     @Test
performClick_toggleTrue_showDirectBootDialog_negative_preferenceEnabled()687     public void performClick_toggleTrue_showDirectBootDialog_negative_preferenceEnabled() {
688         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
689         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
690                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
691         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
692 
693         mControllerHelper.getController().refreshUi();
694 
695         mPreferenceGroup.getPreference(0).performClick();
696 
697         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
698                 ConfirmationDialogFragment.class);
699         verify(mControllerHelper.getMockFragmentController()).showDialog(
700                 securityDialogCaptor.capture(),
701                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
702         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
703 
704         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
705 
706         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
707                 ConfirmationDialogFragment.class);
708         verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
709                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
710         dialogFragment = bootDialogCaptor.getValue();
711 
712         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
713 
714         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
715     }
716 
717     @Test
performClick_toggleTrue_showDirectBootDialog_negative_inputMethodDisabled()718     public void performClick_toggleTrue_showDirectBootDialog_negative_inputMethodDisabled() {
719         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
720         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
721                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
722         getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
723 
724         mControllerHelper.getController().refreshUi();
725 
726         mPreferenceGroup.getPreference(0).performClick();
727 
728         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
729                 ConfirmationDialogFragment.class);
730         verify(mControllerHelper.getMockFragmentController()).showDialog(
731                 securityDialogCaptor.capture(),
732                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
733         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
734 
735         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
736 
737         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
738                 ConfirmationDialogFragment.class);
739         verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
740                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
741         dialogFragment = bootDialogCaptor.getValue();
742 
743         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
744 
745         assertThat(mInputMethodManager.getEnabledInputMethodList().size())
746                 .isEqualTo(0);
747     }
748 
749     @Test
performClick_toggleFalse_noOtherPreferenceAdded()750     public void performClick_toggleFalse_noOtherPreferenceAdded() {
751         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
752         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
753                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
754         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
755                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
756 
757         mControllerHelper.getController().refreshUi();
758 
759         mPreferenceGroup.getPreference(0).performClick();
760 
761         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
762         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
763                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
764     }
765 
766     @Test
performClick_toggleFalse_preferenceNotChecked()767     public void performClick_toggleFalse_preferenceNotChecked() {
768         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
769         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
770                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
771         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
772                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
773 
774         mControllerHelper.getController().refreshUi();
775 
776         mPreferenceGroup.getPreference(0).performClick();
777 
778         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
779                 .isFalse();
780     }
781 
782     @Test
performClick_toggleFalse_preferenceEnabled()783     public void performClick_toggleFalse_preferenceEnabled() {
784         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
785         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
786                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
787         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
788                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
789 
790         mControllerHelper.getController().refreshUi();
791 
792         mPreferenceGroup.getPreference(0).performClick();
793 
794         assertThat((mPreferenceGroup.getPreference(0)).isEnabled())
795                 .isTrue();
796     }
797 
798     @Test
performClick_toggleFalse_inputMethodDisabled()799     public void performClick_toggleFalse_inputMethodDisabled() {
800         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
801         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
802                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
803         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
804                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
805 
806         mControllerHelper.getController().refreshUi();
807 
808         mPreferenceGroup.getPreference(0).performClick();
809 
810         assertThat(mInputMethodManager.getEnabledInputMethodList().size())
811                 .isEqualTo(0);
812     }
813 
814     @Test
performClick_toggleFalse_twoDefaultable_notClickDefaultablePreferenceDisabled()815     public void performClick_toggleFalse_twoDefaultable_notClickDefaultablePreferenceDisabled() {
816         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
817         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
818                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
819                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
820         );
821         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
822                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
823                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
824         );
825 
826         mControllerHelper.getController().refreshUi();
827 
828         getPreferenceFromGroupByKey(mPreferenceGroup, DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE)
829                 .performClick();
830 
831         assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
832                 DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE).isEnabled()).isFalse();
833     }
834 
835     @Test
performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceEnabled()836     public void performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceEnabled() {
837         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
838         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
839                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
840                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
841         );
842         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
843                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
844                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
845         );
846 
847         mControllerHelper.getController().refreshUi();
848 
849         getPreferenceFromGroupByKey(mPreferenceGroup,
850                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
851 
852         assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
853                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).isEnabled()).isTrue();
854     }
855 
856     @Test
performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceEnabled()857     public void performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceEnabled() {
858         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
859         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
860                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
861                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
862         );
863         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
864                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
865                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
866         );
867 
868         mControllerHelper.getController().refreshUi();
869 
870         getPreferenceFromGroupByKey(mPreferenceGroup,
871                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
872 
873         assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
874                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE).isEnabled()).isTrue();
875     }
876 
877     @Test
performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceNotChecked()878     public void performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceNotChecked() {
879         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
880         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
881                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
882                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
883         );
884         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
885                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
886                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
887         );
888 
889         mControllerHelper.getController().refreshUi();
890 
891         getPreferenceFromGroupByKey(mPreferenceGroup,
892                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
893 
894         assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
895                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE)).isChecked()).isFalse();
896     }
897 
898     @Test
performClick_toggleFalse_twoDefaultable_notClickedDefaultablePreferenceChecked()899     public void performClick_toggleFalse_twoDefaultable_notClickedDefaultablePreferenceChecked() {
900         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
901         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
902                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
903                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
904         );
905         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
906                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
907                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
908         );
909 
910         mControllerHelper.getController().refreshUi();
911 
912         getPreferenceFromGroupByKey(mPreferenceGroup,
913                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
914 
915         assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
916                 DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)).isChecked()).isTrue();
917     }
918 
919     @Test
performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceChecked()920     public void performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceChecked() {
921         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
922         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
923                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
924                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
925         );
926         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
927                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
928                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
929         );
930 
931         mControllerHelper.getController().refreshUi();
932 
933         getPreferenceFromGroupByKey(mPreferenceGroup,
934                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
935 
936         assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
937                 DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)).isChecked()).isTrue();
938     }
939 
940     @Test
performClick_toggleTrue_twoDefaultable_allPreferencesEnabled()941     public void performClick_toggleTrue_twoDefaultable_allPreferencesEnabled() {
942         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
943         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
944                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
945                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
946         );
947         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
948                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
949                 DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
950 
951         mControllerHelper.getController().refreshUi();
952 
953         getPreferenceFromGroupByKey(mPreferenceGroup,
954                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
955 
956         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
957                 ConfirmationDialogFragment.class);
958         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
959                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
960         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
961 
962         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
963 
964         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
965             assertThat(mPreferenceGroup.getPreference(i).isEnabled()).isTrue();
966         }
967     }
968 
969     @Test
performClick_toggleTrue_twoDefaultable_allPreferencesChecked()970     public void performClick_toggleTrue_twoDefaultable_allPreferencesChecked() {
971         getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
972         getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
973                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
974                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
975         );
976         getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
977                 ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
978                 DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
979 
980         mControllerHelper.getController().refreshUi();
981 
982         getPreferenceFromGroupByKey(mPreferenceGroup,
983                 DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
984 
985         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
986                 ConfirmationDialogFragment.class);
987         verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
988                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
989         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
990 
991         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
992 
993         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
994             assertThat(((SwitchPreference) mPreferenceGroup.getPreference(i)).isChecked())
995                     .isTrue();
996         }
997     }
998 
createMockInputMethodInfo( Context context, PackageManager packageManager, ShadowInputMethodManager inputMethodManager, String packageName, String id, boolean isDefaultable, boolean directBootAware)999     private static InputMethodInfo createMockInputMethodInfo(
1000             Context context, PackageManager packageManager,
1001             ShadowInputMethodManager inputMethodManager, String packageName, String id,
1002             boolean isDefaultable, boolean directBootAware) {
1003         ServiceInfo mockServiceInfo = mock(ServiceInfo.class);
1004         mockServiceInfo.directBootAware = directBootAware;
1005 
1006         InputMethodInfo mockInfo = mock(InputMethodInfo.class);
1007         when(mockInfo.getPackageName()).thenReturn(packageName);
1008         when(mockInfo.loadLabel(packageManager)).thenReturn(DUMMY_LABEL);
1009         when(mockInfo.getServiceInfo()).thenReturn(mockServiceInfo);
1010         when(mockInfo.getSettingsActivity()).thenReturn(DUMMY_SETTINGS_ACTIVITY);
1011         when(mockInfo.getId()).thenReturn(id);
1012         when(mockInfo.isDefault(context)).thenReturn(isDefaultable);
1013         List<InputMethodSubtype> subtypes = createSubtypes();
1014         inputMethodManager.setEnabledInputMethodSubtypeList(subtypes);
1015         return mockInfo;
1016     }
1017 
getPreferenceFromGroupByKey(PreferenceGroup prefGroup, String key)1018     private static Preference getPreferenceFromGroupByKey(PreferenceGroup prefGroup, String key) {
1019         for (int i = 0; i < prefGroup.getPreferenceCount(); i++) {
1020             Preference pref = prefGroup.getPreference(i);
1021             if (pref.getKey().equals(key)) {
1022                 return pref;
1023             }
1024         }
1025         return null;
1026     }
1027 
createSubtypes()1028     private static List<InputMethodSubtype> createSubtypes() {
1029         List<InputMethodSubtype> subtypes = new ArrayList<>();
1030         subtypes.add(createSubtype(1, "en_US"));
1031         subtypes.add(createSubtype(2, "de_BE"));
1032         subtypes.add(createSubtype(3, "oc-FR"));
1033         return subtypes;
1034     }
1035 
createSubtype(int id, String locale)1036     private static InputMethodSubtype createSubtype(int id, String locale) {
1037         return new InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(id)
1038                 .setSubtypeLocale(locale).setIsAuxiliary(false).setIsAsciiCapable(true).build();
1039     }
1040 
getShadowInputMethodManager(Context context)1041     private static ShadowInputMethodManager getShadowInputMethodManager(Context context) {
1042         return Shadow.extract(context.getSystemService(Context.INPUT_METHOD_SERVICE));
1043     }
1044 
getShadowDevicePolicyManager(Context context)1045     private static ShadowDevicePolicyManager getShadowDevicePolicyManager(Context context) {
1046         return Shadow.extract(context.getSystemService(Context.DEVICE_POLICY_SERVICE));
1047     }
1048 
createInputMethodInfoList(String packageName, String... ids)1049     private List<InputMethodInfo> createInputMethodInfoList(String packageName, String... ids) {
1050         List<InputMethodInfo> infos = new ArrayList<>();
1051         PackageManager packageManager = mContext.getPackageManager();
1052         List<String> idsList = Arrays.asList(ids);
1053         idsList.forEach(id -> {
1054             boolean defaultable;
1055             boolean directBootAware;
1056             switch (id) {
1057                 case DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE:
1058                     defaultable = true;
1059                     directBootAware = true;
1060                     break;
1061                 case DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE:
1062                     defaultable = true;
1063                     directBootAware = false;
1064                     break;
1065                 case DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE:
1066                     defaultable = false;
1067                     directBootAware = true;
1068                     break;
1069                 default: //case DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE:
1070                     defaultable = false;
1071                     directBootAware = false;
1072                     break;
1073             }
1074             infos.add(createMockInputMethodInfo(mContext, packageManager,
1075                     getShadowInputMethodManager(mContext), packageName, id, defaultable,
1076                     directBootAware));
1077         });
1078         return infos;
1079     }
1080 }
1081