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