• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.anyBoolean;
23 import static org.mockito.ArgumentMatchers.eq;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.spy;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28 
29 import android.app.admin.DevicePolicyManager;
30 import android.car.drivingstate.CarUxRestrictions;
31 import android.content.Context;
32 import android.content.DialogInterface;
33 import android.content.pm.PackageManager;
34 import android.content.pm.ServiceInfo;
35 import android.provider.Settings;
36 import android.view.inputmethod.InputMethodInfo;
37 import android.view.inputmethod.InputMethodManager;
38 import android.view.inputmethod.InputMethodSubtype;
39 
40 import androidx.lifecycle.LifecycleOwner;
41 import androidx.preference.Preference;
42 import androidx.preference.PreferenceGroup;
43 import androidx.preference.PreferenceManager;
44 import androidx.preference.PreferenceScreen;
45 import androidx.preference.SwitchPreference;
46 import androidx.test.annotation.UiThreadTest;
47 import androidx.test.core.app.ApplicationProvider;
48 import androidx.test.ext.junit.runners.AndroidJUnit4;
49 
50 import com.android.car.settings.common.ConfirmationDialogFragment;
51 import com.android.car.settings.common.FragmentController;
52 import com.android.car.settings.common.LogicalPreferenceGroup;
53 import com.android.car.settings.common.PreferenceControllerTestUtil;
54 import com.android.car.settings.testutils.TestLifecycleOwner;
55 
56 import org.junit.After;
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.mockito.ArgumentCaptor;
61 import org.mockito.Mock;
62 import org.mockito.MockitoAnnotations;
63 import org.mockito.stubbing.Answer;
64 
65 import java.util.ArrayList;
66 import java.util.Arrays;
67 import java.util.HashMap;
68 import java.util.List;
69 import java.util.Map;
70 import java.util.stream.Collectors;
71 
72 @RunWith(AndroidJUnit4.class)
73 public class KeyboardManagementPreferenceControllerTest {
74     private static final String PLACEHOLDER_LABEL = "placeholder label";
75     private static final String PLACEHOLDER_SETTINGS_ACTIVITY = "placeholder settings activity";
76     private static final String PLACEHOLDER_PACKAGE_NAME = "placeholder package name";
77     private static final String PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE =
78             "placeholder id defaultable direct boot aware";
79     private static final String PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE =
80             "placeholder id defaultable not direct boot aware";
81     private static final String PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE =
82             "placeholder id not defaultable direct boot aware";
83     private static final String PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE =
84             "placeholder id not defaultable not direct boot aware";
85     private static final String DISALLOWED_PACKAGE_NAME = "disallowed package name";
86     private static final String ALLOWED_PACKAGE_NAME = "allowed package name";
87 
88     private Context mContext = spy(ApplicationProvider.getApplicationContext());
89     private LifecycleOwner mLifecycleOwner;
90     private KeyboardManagementPreferenceController mPreferenceController;
91     private LogicalPreferenceGroup mPreferenceGroup;
92     private CarUxRestrictions mCarUxRestrictions;
93     private List<String> mPermittedList;
94     private Map<String, InputMethodInfo> mInputMethodMap;
95     private String mInitialInputMethods;
96 
97     @Mock
98     private FragmentController mMockFragmentController;
99     @Mock
100     private DevicePolicyManager mDevicePolicyManager;
101     @Mock
102     private InputMethodManager mInputMethodManager;
103 
104     @Before
105     @UiThreadTest
setUp()106     public void setUp() {
107         MockitoAnnotations.initMocks(this);
108         mLifecycleOwner = new TestLifecycleOwner();
109 
110         mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
111                 CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
112         mInputMethodMap = new HashMap<>();
113         mPermittedList = new ArrayList<>();
114         mPermittedList.add(PLACEHOLDER_PACKAGE_NAME);
115         mPermittedList.add(ALLOWED_PACKAGE_NAME);
116         mInitialInputMethods = Settings.Secure.getString(mContext.getContentResolver(),
117                 Settings.Secure.ENABLED_INPUT_METHODS);
118 
119         when(mContext.getSystemService(DevicePolicyManager.class)).thenReturn(mDevicePolicyManager);
120         when(mContext.getSystemService(InputMethodManager.class)).thenReturn(mInputMethodManager);
121         when(mInputMethodManager.getInputMethodList()).thenReturn(new ArrayList<>());
122 
123         mPreferenceController = new KeyboardManagementPreferenceController(mContext,
124                 /* preferenceKey= */ "key", mMockFragmentController,
125                 mCarUxRestrictions);
126         PreferenceManager preferenceManager = new PreferenceManager(mContext);
127         PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
128         mPreferenceGroup = new LogicalPreferenceGroup(mContext);
129         screen.addPreference(mPreferenceGroup);
130         PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
131         mPreferenceController.onCreate(mLifecycleOwner);
132     }
133 
134     @After
tearDown()135     public void tearDown() {
136         Settings.Secure.putString(mContext.getContentResolver(),
137                 Settings.Secure.ENABLED_INPUT_METHODS, mInitialInputMethods);
138     }
139 
140     @Test
141     @UiThreadTest
refreshUi_permitAllInputMethods_preferenceCountIs4()142     public void refreshUi_permitAllInputMethods_preferenceCountIs4() {
143         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
144         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
145                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
146                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
147                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
148                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
149         setInputMethodList(infos);
150         setEnabledInputMethodList(infos);
151 
152         mPreferenceController.refreshUi();
153 
154         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(4);
155     }
156 
157     @Test
158     @UiThreadTest
refreshUi_multiplteAllowedImeByOrganization_allPreferencesVisible()159     public void refreshUi_multiplteAllowedImeByOrganization_allPreferencesVisible() {
160         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(
161                 mPermittedList);
162         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
163                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
164                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
165                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
166                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
167         setInputMethodList(infos);
168         setEnabledInputMethodList(infos);
169 
170         mPreferenceController.refreshUi();
171 
172         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
173             assertThat(mPreferenceGroup.getPreference(i).isVisible()).isTrue();
174         }
175     }
176 
177     @Test
178     @UiThreadTest
refreshUi_multipleEnabledInputMethods_allPreferencesEnabled()179     public void refreshUi_multipleEnabledInputMethods_allPreferencesEnabled() {
180         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(
181                 mPermittedList);
182         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
183                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
184                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
185                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
186                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
187         setInputMethodList(infos);
188         setEnabledInputMethodList(infos);
189 
190         mPreferenceController.refreshUi();
191 
192         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
193             assertThat(mPreferenceGroup.getPreference(i).isEnabled()).isTrue();
194         }
195     }
196 
197     @Test
198     @UiThreadTest
refreshUi_multipleEnabledInputMethods_allPreferencesChecked()199     public void refreshUi_multipleEnabledInputMethods_allPreferencesChecked() {
200         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(
201                 mPermittedList);
202         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
203                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
204                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
205                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
206                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
207         setInputMethodList(infos);
208         setEnabledInputMethodList(infos);
209 
210         mPreferenceController.refreshUi();
211 
212         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
213             assertThat(((SwitchPreference) mPreferenceGroup.getPreference(i)).isChecked())
214                     .isTrue();
215         }
216     }
217 
218     @Test
219     @UiThreadTest
refreshUi_disallowedByOrganization_preferenceShownDisabled()220     public void refreshUi_disallowedByOrganization_preferenceShownDisabled() {
221         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(
222                 mPermittedList);
223         List<InputMethodInfo> infos = createInputMethodInfoList(DISALLOWED_PACKAGE_NAME,
224                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
225                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
226                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
227                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
228         setInputMethodList(infos);
229         setEnabledInputMethodList(infos);
230 
231         mPreferenceController.refreshUi();
232 
233         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(infos.size());
234 
235         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
236             SwitchPreference pref = (SwitchPreference) mPreferenceGroup.getPreference(i);
237             assertThat(pref.isVisible()).isTrue();
238             assertThat(pref.isEnabled()).isTrue();
239         }
240     }
241 
242     @Test
243     @UiThreadTest
refreshUi_skipVoiceTyping()244     public void refreshUi_skipVoiceTyping() {
245         // TODO: b/236143731 Add Sufficient Testing to Prevent "Google Voice Typing" Regression
246         for (String gvtPackageName : InputMethodUtil.GVT_PACKAGE_NAMES) {
247             List<InputMethodInfo> infos =
248                     createInputMethodInfoList(gvtPackageName);
249             setInputMethodList(infos);
250 
251             mPreferenceController.refreshUi();
252 
253             assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
254         }
255     }
256 
257     @Test
258     @UiThreadTest
refreshUi_verifyPreferenceIcon()259     public void refreshUi_verifyPreferenceIcon() {
260         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
261         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
262                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
263                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
264                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
265                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
266         setInputMethodList(infos);
267         setEnabledInputMethodList(infos);
268 
269         mPreferenceController.refreshUi();
270 
271         Preference preference = mPreferenceGroup.getPreference(0);
272         assertThat(preference.getIcon()).isEqualTo(
273                 InputMethodUtil.getPackageIcon(mContext.getPackageManager(), infos.get(0)));
274     }
275 
276     @Test
277     @UiThreadTest
refreshUi_verifyPreferenceTitle()278     public void refreshUi_verifyPreferenceTitle() {
279         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
280         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
281                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
282                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
283                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
284                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
285         setInputMethodList(infos);
286         setEnabledInputMethodList(infos);
287 
288         mPreferenceController.refreshUi();
289 
290         Preference preference = mPreferenceGroup.getPreference(0);
291         assertThat(preference.getTitle()).isEqualTo(
292                 InputMethodUtil.getPackageLabel(mContext.getPackageManager(), infos.get(0)));
293     }
294 
295     @Test
296     @UiThreadTest
refreshUi_verifyPreferenceSummary()297     public void refreshUi_verifyPreferenceSummary() {
298         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
299         List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
300                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
301                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
302                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
303                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
304         setInputMethodList(infos);
305         setEnabledInputMethodList(infos);
306 
307         mPreferenceController.refreshUi();
308 
309         Preference preference = mPreferenceGroup.getPreference(0);
310         assertThat(preference.getSummary()).isEqualTo(
311                 InputMethodUtil.getSummaryString(mContext, mInputMethodManager, infos.get(0)));
312     }
313 
314     @Test
315     @UiThreadTest
refreshUi_oneInputMethod_noneEnabled_oneInputMethodPreferenceInView()316     public void refreshUi_oneInputMethod_noneEnabled_oneInputMethodPreferenceInView() {
317         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
318         List<InputMethodInfo> infos = createInputMethodInfoList(
319                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
320         setInputMethodList(infos);
321         setEnabledInputMethodList(new ArrayList<>());
322 
323         mPreferenceController.refreshUi();
324 
325         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
326     }
327 
328     @Test
329     @UiThreadTest
refreshUi_oneInputMethod_noneEnabled_preferenceEnabled()330     public void refreshUi_oneInputMethod_noneEnabled_preferenceEnabled() {
331         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
332         List<InputMethodInfo> infos = createInputMethodInfoList(
333                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
334         setInputMethodList(infos);
335         setEnabledInputMethodList(new ArrayList<>());
336 
337         mPreferenceController.refreshUi();
338 
339         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
340     }
341 
342     @Test
343     @UiThreadTest
refreshUi_oneInputMethod_noneEnabled_preferenceNotChecked()344     public void refreshUi_oneInputMethod_noneEnabled_preferenceNotChecked() {
345         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
346         List<InputMethodInfo> infos = createInputMethodInfoList(
347                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
348         setInputMethodList(infos);
349         setEnabledInputMethodList(new ArrayList<>());
350 
351         mPreferenceController.refreshUi();
352 
353         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
354                 .isFalse();
355     }
356 
357     @Test
358     @UiThreadTest
refreshUi_oneInputMethod_defaultable_notChecked_preferenceEnabled()359     public void refreshUi_oneInputMethod_defaultable_notChecked_preferenceEnabled() {
360         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
361         List<InputMethodInfo> infos = createInputMethodInfoList(
362                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
363         setInputMethodList(infos);
364         setEnabledInputMethodList(new ArrayList<>());
365 
366         mPreferenceController.refreshUi();
367 
368         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
369     }
370 
371     @Test
372     @UiThreadTest
performClick_toggleTrue_securityDialogShown()373     public void performClick_toggleTrue_securityDialogShown() {
374         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
375         List<InputMethodInfo> infos = createInputMethodInfoList(
376                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
377         setInputMethodList(infos);
378         setEnabledInputMethodList(new ArrayList<>());
379 
380         mPreferenceController.refreshUi();
381 
382         mPreferenceGroup.getPreference(0).performClick();
383 
384         verify(mMockFragmentController).showDialog(
385                 any(ConfirmationDialogFragment.class),
386                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
387     }
388 
389     @Test
390     @UiThreadTest
performClick_toggleTrue_showSecurityDialog_positive_noOtherPreferenceAdded()391     public void performClick_toggleTrue_showSecurityDialog_positive_noOtherPreferenceAdded() {
392         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
393         List<InputMethodInfo> infos = createInputMethodInfoList(
394                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
395         setInputMethodList(infos);
396         setEnabledInputMethodList(new ArrayList<>());
397 
398         mPreferenceController.refreshUi();
399 
400         mPreferenceGroup.getPreference(0).performClick();
401 
402         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
403                 ConfirmationDialogFragment.class);
404         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
405                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
406         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
407 
408         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
409 
410         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
411         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
412                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
413     }
414 
415     @Test
416     @UiThreadTest
performClick_toggleTrue_showSecurityDialog_positive_preferenceChecked()417     public void performClick_toggleTrue_showSecurityDialog_positive_preferenceChecked() {
418         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
419         List<InputMethodInfo> infos = createInputMethodInfoList(
420                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
421         setInputMethodList(infos);
422         setEnabledInputMethodList(new ArrayList<>());
423 
424         mPreferenceController.refreshUi();
425 
426         mPreferenceGroup.getPreference(0).performClick();
427 
428         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
429                 ConfirmationDialogFragment.class);
430         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
431                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
432         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
433 
434         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
435 
436         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
437                 .isTrue();
438     }
439 
440     @Test
441     @UiThreadTest
performClick_toggleTrue_showSecurityDialog_positive_preferenceEnabled()442     public void performClick_toggleTrue_showSecurityDialog_positive_preferenceEnabled() {
443         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
444         List<InputMethodInfo> infos = createInputMethodInfoList(
445                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
446         setInputMethodList(infos);
447         setEnabledInputMethodList(new ArrayList<>());
448 
449         mPreferenceController.refreshUi();
450 
451         mPreferenceGroup.getPreference(0).performClick();
452 
453         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
454                 ConfirmationDialogFragment.class);
455         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
456                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
457         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
458 
459         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
460 
461         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
462     }
463 
464     @Test
465     @UiThreadTest
performClick_toggleTrue_showSecurityDialog_positive_inputMethodEnabled()466     public void performClick_toggleTrue_showSecurityDialog_positive_inputMethodEnabled() {
467         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
468         List<InputMethodInfo> infos = createInputMethodInfoList(
469                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
470         setInputMethodList(infos);
471         setEnabledInputMethodList(new ArrayList<>());
472 
473         mPreferenceController.refreshUi();
474 
475         mPreferenceGroup.getPreference(0).performClick();
476 
477         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
478                 ConfirmationDialogFragment.class);
479         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
480                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
481         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
482 
483         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
484 
485         assertThat(getEnabledInputMethodList().get(0).getId())
486                 .isEqualTo(PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
487     }
488 
489     @Test
490     @UiThreadTest
performClick_toggleTrue_showSecurityDialog_negative_noOtherPreferenceAdded()491     public void performClick_toggleTrue_showSecurityDialog_negative_noOtherPreferenceAdded() {
492         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
493         List<InputMethodInfo> infos = createInputMethodInfoList(
494                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
495         setInputMethodList(infos);
496         setEnabledInputMethodList(new ArrayList<>());
497 
498         mPreferenceController.refreshUi();
499 
500         mPreferenceGroup.getPreference(0).performClick();
501 
502         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
503                 ConfirmationDialogFragment.class);
504         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
505                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
506         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
507 
508         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
509 
510         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
511         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
512                 PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
513     }
514 
515     @Test
516     @UiThreadTest
performClick_toggleTrue_showSecurityDialog_negative_preferenceEnabled()517     public void performClick_toggleTrue_showSecurityDialog_negative_preferenceEnabled() {
518         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
519         List<InputMethodInfo> infos = createInputMethodInfoList(
520                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
521         setInputMethodList(infos);
522         setEnabledInputMethodList(new ArrayList<>());
523 
524         mPreferenceController.refreshUi();
525 
526         mPreferenceGroup.getPreference(0).performClick();
527 
528         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
529                 ConfirmationDialogFragment.class);
530         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
531                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
532         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
533 
534         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
535 
536         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
537     }
538 
539     @Test
540     @UiThreadTest
performClick_toggleTrue_showSecurityDialog_negative_inputMethodDisabled()541     public void performClick_toggleTrue_showSecurityDialog_negative_inputMethodDisabled() {
542         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
543         List<InputMethodInfo> infos = createInputMethodInfoList(
544                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
545         setInputMethodList(infos);
546         setEnabledInputMethodList(new ArrayList<>());
547 
548         mPreferenceController.refreshUi();
549 
550         mPreferenceGroup.getPreference(0).performClick();
551 
552         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
553                 ConfirmationDialogFragment.class);
554         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
555                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
556         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
557 
558         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
559 
560         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
561                 .isFalse();
562     }
563 
564     @Test
565     @UiThreadTest
performClick_toggleTrue_directBootWarningShown()566     public void performClick_toggleTrue_directBootWarningShown() {
567         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
568         List<InputMethodInfo> infos = createInputMethodInfoList(
569                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
570         setInputMethodList(infos);
571         setEnabledInputMethodList(new ArrayList<>());
572 
573         mPreferenceController.refreshUi();
574 
575         mPreferenceGroup.getPreference(0).performClick();
576 
577         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
578                 ConfirmationDialogFragment.class);
579         verify(mMockFragmentController).showDialog(
580                 securityDialogCaptor.capture(),
581                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
582         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
583 
584         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
585 
586 
587         verify(mMockFragmentController).showDialog(
588                 any(ConfirmationDialogFragment.class),
589                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
590     }
591 
592     @Test
593     @UiThreadTest
performClick_toggleTrue_showDirectBootDialog_positive_noOtherPreferenceAdded()594     public void performClick_toggleTrue_showDirectBootDialog_positive_noOtherPreferenceAdded() {
595         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
596         List<InputMethodInfo> infos = createInputMethodInfoList(
597                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
598         setInputMethodList(infos);
599         setEnabledInputMethodList(new ArrayList<>());
600 
601         mPreferenceController.refreshUi();
602 
603         mPreferenceGroup.getPreference(0).performClick();
604 
605         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
606                 ConfirmationDialogFragment.class);
607         verify(mMockFragmentController).showDialog(
608                 securityDialogCaptor.capture(),
609                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
610         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
611 
612         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
613 
614         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
615                 ConfirmationDialogFragment.class);
616         verify(mMockFragmentController).showDialog(bootDialogCaptor.capture(),
617                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
618         dialogFragment = bootDialogCaptor.getValue();
619 
620         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
621 
622         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
623         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
624                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
625     }
626 
627     @Test
628     @UiThreadTest
performClick_toggleTrue_showDirectBootDialog_positive_preferenceChecked()629     public void performClick_toggleTrue_showDirectBootDialog_positive_preferenceChecked() {
630         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
631         List<InputMethodInfo> infos = createInputMethodInfoList(
632                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
633         setInputMethodList(infos);
634         setEnabledInputMethodList(new ArrayList<>());
635 
636         mPreferenceController.refreshUi();
637 
638         mPreferenceGroup.getPreference(0).performClick();
639 
640         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
641                 ConfirmationDialogFragment.class);
642         verify(mMockFragmentController).showDialog(
643                 securityDialogCaptor.capture(),
644                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
645         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
646 
647         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
648 
649         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
650                 ConfirmationDialogFragment.class);
651         verify(mMockFragmentController).showDialog(bootDialogCaptor.capture(),
652                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
653         dialogFragment = bootDialogCaptor.getValue();
654 
655         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
656 
657         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
658                 .isTrue();
659     }
660 
661     @Test
662     @UiThreadTest
performClick_toggleTrue_showDirectBootDialog_positive_preferenceEnabled()663     public void performClick_toggleTrue_showDirectBootDialog_positive_preferenceEnabled() {
664         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
665         List<InputMethodInfo> infos = createInputMethodInfoList(
666                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
667         setInputMethodList(infos);
668         setEnabledInputMethodList(new ArrayList<>());
669 
670         mPreferenceController.refreshUi();
671 
672         mPreferenceGroup.getPreference(0).performClick();
673 
674         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
675                 ConfirmationDialogFragment.class);
676         verify(mMockFragmentController).showDialog(
677                 securityDialogCaptor.capture(),
678                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
679         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
680 
681         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
682 
683         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
684                 ConfirmationDialogFragment.class);
685         verify(mMockFragmentController).showDialog(bootDialogCaptor.capture(),
686                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
687         dialogFragment = bootDialogCaptor.getValue();
688 
689         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
690 
691         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
692     }
693 
694     @Test
695     @UiThreadTest
performClick_toggleTrue_showDirectBootDialog_positive_inputMethodEnabled()696     public void performClick_toggleTrue_showDirectBootDialog_positive_inputMethodEnabled() {
697         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
698         List<InputMethodInfo> infos = createInputMethodInfoList(
699                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
700         setInputMethodList(infos);
701         setEnabledInputMethodList(new ArrayList<>());
702 
703         mPreferenceController.refreshUi();
704 
705         mPreferenceGroup.getPreference(0).performClick();
706 
707         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
708                 ConfirmationDialogFragment.class);
709         verify(mMockFragmentController).showDialog(
710                 securityDialogCaptor.capture(),
711                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
712         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
713 
714         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
715 
716         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
717                 ConfirmationDialogFragment.class);
718         verify(mMockFragmentController).showDialog(bootDialogCaptor.capture(),
719                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
720         dialogFragment = bootDialogCaptor.getValue();
721 
722         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
723 
724         assertThat(getEnabledInputMethodList().get(0).getId())
725                 .isEqualTo(PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
726     }
727 
728     @Test
729     @UiThreadTest
performClick_toggleTrue_showDirectBootDialog_negative_noOtherPreferenceAdded()730     public void performClick_toggleTrue_showDirectBootDialog_negative_noOtherPreferenceAdded() {
731         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
732         List<InputMethodInfo> infos = createInputMethodInfoList(
733                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
734         setInputMethodList(infos);
735         setEnabledInputMethodList(new ArrayList<>());
736 
737         mPreferenceController.refreshUi();
738 
739         mPreferenceGroup.getPreference(0).performClick();
740 
741         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
742                 ConfirmationDialogFragment.class);
743         verify(mMockFragmentController).showDialog(
744                 securityDialogCaptor.capture(),
745                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
746         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
747 
748         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
749 
750         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
751                 ConfirmationDialogFragment.class);
752         verify(mMockFragmentController).showDialog(bootDialogCaptor.capture(),
753                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
754         dialogFragment = bootDialogCaptor.getValue();
755 
756         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
757 
758 
759         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
760         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
761                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
762     }
763 
764     @Test
765     @UiThreadTest
performClick_toggleTrue_showDirectBootDialog_negative_preferenceNotChecked()766     public void performClick_toggleTrue_showDirectBootDialog_negative_preferenceNotChecked() {
767         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
768         List<InputMethodInfo> infos = createInputMethodInfoList(
769                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
770         setInputMethodList(infos);
771         setEnabledInputMethodList(new ArrayList<>());
772 
773         mPreferenceController.refreshUi();
774 
775         mPreferenceGroup.getPreference(0).performClick();
776 
777         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
778                 ConfirmationDialogFragment.class);
779         verify(mMockFragmentController).showDialog(
780                 securityDialogCaptor.capture(),
781                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
782         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
783 
784         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
785 
786         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
787                 ConfirmationDialogFragment.class);
788         verify(mMockFragmentController).showDialog(bootDialogCaptor.capture(),
789                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
790         dialogFragment = bootDialogCaptor.getValue();
791 
792         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
793 
794 
795         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
796                 .isFalse();
797     }
798 
799     @Test
800     @UiThreadTest
performClick_toggleTrue_showDirectBootDialog_negative_preferenceEnabled()801     public void performClick_toggleTrue_showDirectBootDialog_negative_preferenceEnabled() {
802         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
803         List<InputMethodInfo> infos = createInputMethodInfoList(
804                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
805         setInputMethodList(infos);
806         setEnabledInputMethodList(new ArrayList<>());
807 
808         mPreferenceController.refreshUi();
809 
810         mPreferenceGroup.getPreference(0).performClick();
811 
812         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
813                 ConfirmationDialogFragment.class);
814         verify(mMockFragmentController).showDialog(
815                 securityDialogCaptor.capture(),
816                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
817         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
818 
819         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
820 
821         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
822                 ConfirmationDialogFragment.class);
823         verify(mMockFragmentController).showDialog(bootDialogCaptor.capture(),
824                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
825         dialogFragment = bootDialogCaptor.getValue();
826 
827         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
828 
829         assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
830     }
831 
832     @Test
833     @UiThreadTest
performClick_toggleTrue_showDirectBootDialog_negative_inputMethodDisabled()834     public void performClick_toggleTrue_showDirectBootDialog_negative_inputMethodDisabled() {
835         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
836         List<InputMethodInfo> infos = createInputMethodInfoList(
837                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
838         setInputMethodList(infos);
839         setEnabledInputMethodList(new ArrayList<>());
840 
841         mPreferenceController.refreshUi();
842 
843         mPreferenceGroup.getPreference(0).performClick();
844 
845         ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
846                 ConfirmationDialogFragment.class);
847         verify(mMockFragmentController).showDialog(
848                 securityDialogCaptor.capture(),
849                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
850         ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
851 
852         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
853 
854         ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
855                 ConfirmationDialogFragment.class);
856         verify(mMockFragmentController).showDialog(bootDialogCaptor.capture(),
857                 eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
858         dialogFragment = bootDialogCaptor.getValue();
859 
860         dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
861 
862         assertThat(mInputMethodManager.getEnabledInputMethodList().size())
863                 .isEqualTo(0);
864     }
865 
866     @Test
867     @UiThreadTest
performClick_toggleFalse_noOtherPreferenceAdded()868     public void performClick_toggleFalse_noOtherPreferenceAdded() {
869         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
870         List<InputMethodInfo> infos = createInputMethodInfoList(
871                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
872         setInputMethodList(infos);
873         setEnabledInputMethodList(infos);
874 
875         mPreferenceController.refreshUi();
876 
877         mPreferenceGroup.getPreference(0).performClick();
878 
879         assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
880         assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
881                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
882     }
883 
884     @Test
885     @UiThreadTest
performClick_toggleFalse_preferenceNotChecked()886     public void performClick_toggleFalse_preferenceNotChecked() {
887         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
888         List<InputMethodInfo> infos = createInputMethodInfoList(
889                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
890         setInputMethodList(infos);
891         setEnabledInputMethodList(infos);
892 
893         mPreferenceController.refreshUi();
894 
895         mPreferenceGroup.getPreference(0).performClick();
896 
897         assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
898                 .isFalse();
899     }
900 
901     @Test
902     @UiThreadTest
performClick_toggleFalse_preferenceEnabled()903     public void performClick_toggleFalse_preferenceEnabled() {
904         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
905         List<InputMethodInfo> infos = createInputMethodInfoList(
906                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
907         setInputMethodList(infos);
908         setEnabledInputMethodList(infos);
909 
910         mPreferenceController.refreshUi();
911 
912         mPreferenceGroup.getPreference(0).performClick();
913 
914         assertThat((mPreferenceGroup.getPreference(0)).isEnabled())
915                 .isTrue();
916     }
917 
918     @Test
919     @UiThreadTest
performClick_toggleFalse_inputMethodDisabled()920     public void performClick_toggleFalse_inputMethodDisabled() {
921         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
922         List<InputMethodInfo> infos = createInputMethodInfoList(
923                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
924         setInputMethodList(infos);
925         setEnabledInputMethodList(infos);
926 
927         mPreferenceController.refreshUi();
928 
929         mPreferenceGroup.getPreference(0).performClick();
930 
931         assertThat(mInputMethodManager.getEnabledInputMethodList().size())
932                 .isEqualTo(0);
933     }
934 
935     @Test
936     @UiThreadTest
performClick_toggleFalse_twoDefaultable_notClickDefaultablePreferenceDisabled()937     public void performClick_toggleFalse_twoDefaultable_notClickDefaultablePreferenceDisabled() {
938         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
939         List<InputMethodInfo> infos = createInputMethodInfoList(
940                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
941                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
942                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
943         setInputMethodList(infos);
944         setEnabledInputMethodList(infos);
945 
946         mPreferenceController.refreshUi();
947 
948         getPreferenceFromGroupByKey(mPreferenceGroup, PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE)
949                 .performClick();
950 
951         assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
952                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE).isEnabled()).isFalse();
953     }
954 
955     @Test
956     @UiThreadTest
performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceEnabled()957     public void performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceEnabled() {
958         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
959         List<InputMethodInfo> infos = createInputMethodInfoList(
960                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
961                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
962                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
963         setInputMethodList(infos);
964         setEnabledInputMethodList(infos);
965 
966         mPreferenceController.refreshUi();
967 
968         getPreferenceFromGroupByKey(mPreferenceGroup,
969                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
970 
971         assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
972                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).isEnabled()).isTrue();
973     }
974 
975     @Test
976     @UiThreadTest
performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceEnabled()977     public void performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceEnabled() {
978         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
979         List<InputMethodInfo> infos = createInputMethodInfoList(
980                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
981                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
982                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
983         setInputMethodList(infos);
984         setEnabledInputMethodList(infos);
985 
986         mPreferenceController.refreshUi();
987 
988         getPreferenceFromGroupByKey(mPreferenceGroup,
989                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
990 
991         assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
992                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE).isEnabled()).isTrue();
993     }
994 
995     @Test
996     @UiThreadTest
performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceNotChecked()997     public void performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceNotChecked() {
998         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
999         List<InputMethodInfo> infos = createInputMethodInfoList(
1000                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
1001                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
1002                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
1003         setInputMethodList(infos);
1004         setEnabledInputMethodList(infos);
1005 
1006         mPreferenceController.refreshUi();
1007 
1008         getPreferenceFromGroupByKey(mPreferenceGroup,
1009                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
1010 
1011         assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
1012                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE)).isChecked()).isFalse();
1013     }
1014 
1015     @Test
1016     @UiThreadTest
performClick_toggleFalse_twoDefaultable_notClickedDefaultablePreferenceChecked()1017     public void performClick_toggleFalse_twoDefaultable_notClickedDefaultablePreferenceChecked() {
1018         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
1019         List<InputMethodInfo> infos = createInputMethodInfoList(
1020                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
1021                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
1022                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
1023         setInputMethodList(infos);
1024         setEnabledInputMethodList(infos);
1025 
1026         mPreferenceController.refreshUi();
1027 
1028         getPreferenceFromGroupByKey(mPreferenceGroup,
1029                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
1030 
1031         assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
1032                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)).isChecked()).isTrue();
1033     }
1034 
1035     @Test
1036     @UiThreadTest
performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceChecked()1037     public void performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceChecked() {
1038         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
1039         List<InputMethodInfo> infos = createInputMethodInfoList(
1040                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
1041                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
1042                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
1043         setInputMethodList(infos);
1044         setEnabledInputMethodList(infos);
1045 
1046         mPreferenceController.refreshUi();
1047 
1048         getPreferenceFromGroupByKey(mPreferenceGroup,
1049                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
1050 
1051         assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
1052                 PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)).isChecked()).isTrue();
1053     }
1054 
1055     @Test
1056     @UiThreadTest
performClick_toggleTrue_twoDefaultable_allPreferencesEnabled()1057     public void performClick_toggleTrue_twoDefaultable_allPreferencesEnabled() {
1058         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
1059         List<InputMethodInfo> infos = createInputMethodInfoList(
1060                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
1061                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
1062                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
1063         setInputMethodList(infos);
1064         List<InputMethodInfo> infos2 = createInputMethodInfoList(
1065                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
1066                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
1067         setEnabledInputMethodList(infos2);
1068 
1069         mPreferenceController.refreshUi();
1070 
1071         getPreferenceFromGroupByKey(mPreferenceGroup,
1072                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
1073 
1074         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
1075                 ConfirmationDialogFragment.class);
1076         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
1077                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
1078         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
1079 
1080         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
1081 
1082         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
1083             assertThat(mPreferenceGroup.getPreference(i).isEnabled()).isTrue();
1084         }
1085     }
1086 
1087     @Test
1088     @UiThreadTest
performClick_toggleTrue_twoDefaultable_allPreferencesChecked()1089     public void performClick_toggleTrue_twoDefaultable_allPreferencesChecked() {
1090         when(mDevicePolicyManager.getPermittedInputMethodsForCurrentUser()).thenReturn(null);
1091         List<InputMethodInfo> infos = createInputMethodInfoList(
1092                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
1093                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE,
1094                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
1095         setInputMethodList(infos);
1096         List<InputMethodInfo> infos2 = createInputMethodInfoList(
1097                 ALLOWED_PACKAGE_NAME, PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
1098                 PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
1099         setEnabledInputMethodList(infos2);
1100 
1101         mPreferenceController.refreshUi();
1102 
1103         getPreferenceFromGroupByKey(mPreferenceGroup,
1104                 PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
1105 
1106         ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
1107                 ConfirmationDialogFragment.class);
1108         verify(mMockFragmentController).showDialog(dialogCaptor.capture(),
1109                 eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
1110         ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
1111 
1112         dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
1113 
1114         for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
1115             assertThat(((SwitchPreference) mPreferenceGroup.getPreference(i)).isChecked())
1116                     .isTrue();
1117         }
1118     }
1119 
createMockInputMethodInfo( Context context, PackageManager packageManager, String packageName, String id, boolean isDefaultable, boolean directBootAware)1120     private InputMethodInfo createMockInputMethodInfo(
1121             Context context, PackageManager packageManager,
1122             String packageName, String id, boolean isDefaultable, boolean directBootAware) {
1123         ServiceInfo mockServiceInfo = mock(ServiceInfo.class);
1124         mockServiceInfo.directBootAware = directBootAware;
1125 
1126         InputMethodInfo mockInfo = mock(InputMethodInfo.class);
1127         when(mockInfo.getPackageName()).thenReturn(packageName);
1128         when(mockInfo.loadLabel(packageManager)).thenReturn(PLACEHOLDER_LABEL);
1129         when(mockInfo.getServiceInfo()).thenReturn(mockServiceInfo);
1130         when(mockInfo.getSettingsActivity()).thenReturn(PLACEHOLDER_SETTINGS_ACTIVITY);
1131         when(mockInfo.getId()).thenReturn(id);
1132         when(mockInfo.isDefault(context)).thenReturn(isDefaultable);
1133         List<InputMethodSubtype> subtypes = createSubtypes();
1134         when(mInputMethodManager.getEnabledInputMethodSubtypeList(any(), anyBoolean()))
1135                 .thenReturn(subtypes);
1136         return mockInfo;
1137     }
1138 
getPreferenceFromGroupByKey(PreferenceGroup prefGroup, String key)1139     private static Preference getPreferenceFromGroupByKey(PreferenceGroup prefGroup, String key) {
1140         for (int i = 0; i < prefGroup.getPreferenceCount(); i++) {
1141             Preference pref = prefGroup.getPreference(i);
1142             if (pref.getKey().equals(key)) {
1143                 return pref;
1144             }
1145         }
1146         return null;
1147     }
1148 
createSubtypes()1149     private static List<InputMethodSubtype> createSubtypes() {
1150         List<InputMethodSubtype> subtypes = new ArrayList<>();
1151         subtypes.add(createSubtype(1, "en_US"));
1152         subtypes.add(createSubtype(2, "de_BE"));
1153         subtypes.add(createSubtype(3, "oc-FR"));
1154         return subtypes;
1155     }
1156 
createSubtype(int id, String locale)1157     private static InputMethodSubtype createSubtype(int id, String locale) {
1158         return new InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(id)
1159                 .setSubtypeLocale(locale).setIsAuxiliary(false).setIsAsciiCapable(true).build();
1160     }
1161 
createInputMethodInfoList(String packageName, String... ids)1162     private List<InputMethodInfo> createInputMethodInfoList(String packageName, String... ids) {
1163         List<InputMethodInfo> infos = new ArrayList<>();
1164         PackageManager packageManager = mContext.getPackageManager();
1165         List<String> idsList = Arrays.asList(ids);
1166         idsList.forEach(id -> {
1167             boolean defaultable;
1168             boolean directBootAware;
1169             switch (id) {
1170                 case PLACEHOLDER_ID_DEFAULTABLE_DIRECT_BOOT_AWARE:
1171                     defaultable = true;
1172                     directBootAware = true;
1173                     break;
1174                 case PLACEHOLDER_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE:
1175                     defaultable = true;
1176                     directBootAware = false;
1177                     break;
1178                 case PLACEHOLDER_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE:
1179                     defaultable = false;
1180                     directBootAware = true;
1181                     break;
1182                 default: //case PLACEHOLDER_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE:
1183                     defaultable = false;
1184                     directBootAware = false;
1185                     break;
1186             }
1187             infos.add(createMockInputMethodInfo(mContext, packageManager, packageName, id,
1188                     defaultable, directBootAware));
1189         });
1190         return infos;
1191     }
1192 
setInputMethodList(List<InputMethodInfo> list)1193     private void setInputMethodList(List<InputMethodInfo> list) {
1194         when(mInputMethodManager.getInputMethodList()).thenReturn(list);
1195         if (list != null && list.size() > 0) {
1196             addInputMethodInfosToMap(list);
1197         }
1198     }
1199 
setEnabledInputMethodList(List<InputMethodInfo> list)1200     private void setEnabledInputMethodList(List<InputMethodInfo> list) {
1201         if (list == null || list.size() == 0) {
1202             Settings.Secure.putString(mContext.getContentResolver(),
1203                     Settings.Secure.ENABLED_INPUT_METHODS, "");
1204             return;
1205         }
1206 
1207         String concatenatedInputMethodIds = createInputMethodIdString(list.stream().map(
1208                 imi -> imi.getId()).collect(Collectors.toList()).toArray(new String[list.size()]));
1209         Settings.Secure.putString(mContext.getContentResolver(),
1210                 Settings.Secure.ENABLED_INPUT_METHODS, concatenatedInputMethodIds);
1211         addInputMethodInfosToMap(list);
1212         when(mInputMethodManager.getEnabledInputMethodList()).thenAnswer(
1213                 (Answer<List<InputMethodInfo>>) invocation -> getEnabledInputMethodList());
1214     }
1215 
getEnabledInputMethodList()1216     private List<InputMethodInfo> getEnabledInputMethodList() {
1217         List<InputMethodInfo> enabledInputMethodList = new ArrayList<>();
1218 
1219         String inputMethodIdString = Settings.Secure.getString(
1220                 mContext.getContentResolver(),
1221                 Settings.Secure.ENABLED_INPUT_METHODS);
1222         if (inputMethodIdString == null || inputMethodIdString.isEmpty()) {
1223             return enabledInputMethodList;
1224         }
1225 
1226         InputMethodUtil.sInputMethodSplitter.setString(inputMethodIdString);
1227         while (InputMethodUtil.sInputMethodSplitter.hasNext()) {
1228             enabledInputMethodList.add(mInputMethodMap.get(InputMethodUtil.sInputMethodSplitter
1229                     .next()));
1230         }
1231         return enabledInputMethodList;
1232     }
1233 
createInputMethodIdString(String... ids)1234     private String createInputMethodIdString(String... ids) {
1235         int size = ids == null ? 0 : ids.length;
1236 
1237         if (size == 1) {
1238             return ids[0];
1239         }
1240 
1241         StringBuilder builder = new StringBuilder();
1242         for (int i = 0; i < size; i++) {
1243             builder.append(ids[i]);
1244             if (i != size - 1) {
1245                 builder.append(InputMethodUtil.INPUT_METHOD_DELIMITER);
1246             }
1247         }
1248         return builder.toString();
1249     }
1250 
addInputMethodInfosToMap(List<InputMethodInfo> inputMethodInfos)1251     private void addInputMethodInfosToMap(List<InputMethodInfo> inputMethodInfos) {
1252         if (mInputMethodMap == null || mInputMethodMap.size() == 0) {
1253             mInputMethodMap = inputMethodInfos.stream().collect(Collectors.toMap(
1254                     InputMethodInfo::getId, imi -> imi));
1255             return;
1256         }
1257 
1258         inputMethodInfos.forEach(imi -> {
1259             mInputMethodMap.put(imi.getId(), imi);
1260         });
1261     }
1262 }
1263