Merge "DO NOT MERGE Extract Bluetooth device scanning logic into abstract superclass." into pi-car-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a0491db..a890aed 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -412,6 +412,8 @@
         <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g> additional permission</item>
         <item quantity="other"><xliff:g example="10" id="count">%d</xliff:g> additional permissions</item>
     </plurals>
+    <!-- Dialog body explaining that the app just selected by the user will not work after a reboot until after the user enters their credentials, such as a PIN or password. [CHAR LIMIT=NONE] -->
+    <string name="direct_boot_unaware_dialog_message_car">Note: After a reboot, this app can\'t start until you unlock your vehicle.</string>
     <!-- Assistant and voice input settings title. This setting goes into the manage assistant settings page. [CHAR LIMIT=40] -->
     <string name="assist_and_voice_input_settings">Assist &amp; voice input</string>
     <!-- Default assistant settings title. This setting allows users to select the default assistant for the device. [CHAR LIMIT=40] -->
diff --git a/src/com/android/car/settings/inputmethod/InputMethodUtil.java b/src/com/android/car/settings/inputmethod/InputMethodUtil.java
index 585ee2c..8100b02 100644
--- a/src/com/android/car/settings/inputmethod/InputMethodUtil.java
+++ b/src/com/android/car/settings/inputmethod/InputMethodUtil.java
@@ -16,12 +16,15 @@
 
 package com.android.car.settings.inputmethod;
 
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.provider.Settings;
+import android.text.TextUtils;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
@@ -35,9 +38,21 @@
 
 /** Keyboard utility class. */
 public final class InputMethodUtil {
+    /**
+     * Delimiter for Enabled Input Methods' concatenated string.
+     */
+    public static final char INPUT_METHOD_DELIMITER = ':';
+    /**
+     * Splitter for Enabled Input Methods' concatenated string.
+     */
+    public static final TextUtils.SimpleStringSplitter sInputMethodSplitter =
+            new TextUtils.SimpleStringSplitter(INPUT_METHOD_DELIMITER);
     @VisibleForTesting
     static final Drawable NO_ICON = new ColorDrawable(Color.TRANSPARENT);
 
+    private InputMethodUtil() {
+    }
+
     /** Returns package icon. */
     public static Drawable getPackageIcon(@NonNull PackageManager packageManager,
             @NonNull InputMethodInfo inputMethodInfo) {
@@ -68,5 +83,104 @@
                 subtypes, context, inputMethodInfo);
     }
 
-    private InputMethodUtil() {}
+    /**
+     * Check if input method is enabled.
+     *
+     * @return {@code true} if the input method is enabled.
+     */
+    public static boolean isInputMethodEnabled(ContentResolver resolver,
+            InputMethodInfo inputMethodInfo) {
+        sInputMethodSplitter.setString(getEnabledInputMethodsConcatenatedIds(resolver));
+        while (sInputMethodSplitter.hasNext()) {
+            String inputMethodId = sInputMethodSplitter.next();
+            if (inputMethodId.equals(inputMethodInfo.getId())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Enable an input method using its InputMethodInfo.
+     */
+    public static void enableInputMethod(ContentResolver resolver,
+            InputMethodInfo inputMethodInfo) {
+        if (isInputMethodEnabled(resolver, inputMethodInfo)) {
+            return;
+        }
+
+        StringBuilder builder = new StringBuilder();
+        builder.append(getEnabledInputMethodsConcatenatedIds(resolver));
+
+        if (!builder.toString().isEmpty()) {
+            builder.append(INPUT_METHOD_DELIMITER);
+        }
+
+        builder.append(inputMethodInfo.getId());
+
+        setEnabledInputMethodsConcatenatedIds(resolver, builder.toString());
+    }
+
+    /**
+     * Disable an input method if its not the default system input method or if there exists another
+     * enabled input method that can also be set as the default system input method.
+     */
+    public static void disableInputMethod(Context context, InputMethodManager inputMethodManager,
+            InputMethodInfo inputMethodInfo) {
+        List<InputMethodInfo> enabledInputMethodInfos = inputMethodManager
+                .getEnabledInputMethodList();
+        StringBuilder builder = new StringBuilder();
+
+        boolean foundAnotherEnabledDefaultInputMethod = false;
+        boolean isSystemDefault = isDefaultInputMethod(context.getContentResolver(),
+                inputMethodInfo);
+        for (InputMethodInfo enabledInputMethodInfo : enabledInputMethodInfos) {
+            if (enabledInputMethodInfo.getId().equals(inputMethodInfo.getId())) {
+                continue;
+            }
+
+            if (builder.length() > 0) {
+                builder.append(INPUT_METHOD_DELIMITER);
+            }
+
+            builder.append(enabledInputMethodInfo.getId());
+
+            if (isSystemDefault && enabledInputMethodInfo.isDefault(context)) {
+                foundAnotherEnabledDefaultInputMethod = true;
+                setDefaultInputMethodId(context.getContentResolver(),
+                        enabledInputMethodInfo.getId());
+            }
+        }
+
+        if (isSystemDefault && !foundAnotherEnabledDefaultInputMethod) {
+            return;
+        }
+
+        setEnabledInputMethodsConcatenatedIds(context.getContentResolver(), builder.toString());
+    }
+
+    private static String getEnabledInputMethodsConcatenatedIds(ContentResolver resolver) {
+        return Settings.Secure.getString(resolver, Settings.Secure.ENABLED_INPUT_METHODS);
+    }
+
+    private static String getDefaultInputMethodId(ContentResolver resolver) {
+        return Settings.Secure.getString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD);
+    }
+
+    private static boolean isDefaultInputMethod(ContentResolver resolver,
+            InputMethodInfo inputMethodInfo) {
+        return inputMethodInfo.getId().equals(getDefaultInputMethodId(resolver));
+    }
+
+    private static void setEnabledInputMethodsConcatenatedIds(ContentResolver resolver,
+            String enabledInputMethodIds) {
+        Settings.Secure.putString(resolver, Settings.Secure.ENABLED_INPUT_METHODS,
+                enabledInputMethodIds);
+    }
+
+    private static void setDefaultInputMethodId(ContentResolver resolver,
+            String defaultInputMethodId) {
+        Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD,
+                defaultInputMethodId);
+    }
 }
diff --git a/src/com/android/car/settings/inputmethod/KeyboardManagementPreferenceController.java b/src/com/android/car/settings/inputmethod/KeyboardManagementPreferenceController.java
index 8f6da1b..e643867 100644
--- a/src/com/android/car/settings/inputmethod/KeyboardManagementPreferenceController.java
+++ b/src/com/android/car/settings/inputmethod/KeyboardManagementPreferenceController.java
@@ -16,21 +16,89 @@
 
 package com.android.car.settings.inputmethod;
 
+import android.app.admin.DevicePolicyManager;
 import android.car.drivingstate.CarUxRestrictions;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
 
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
 import androidx.preference.PreferenceGroup;
+import androidx.preference.SwitchPreference;
 
+import com.android.car.settings.R;
+import com.android.car.settings.common.ConfirmationDialogFragment;
 import com.android.car.settings.common.FragmentController;
 import com.android.car.settings.common.PreferenceController;
 
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 /** Updates the available keyboard list. */
 public class KeyboardManagementPreferenceController extends
         PreferenceController<PreferenceGroup> {
+    @VisibleForTesting
+    static final String DIRECT_BOOT_WARN_DIALOG_TAG = "DirectBootWarnDialog";
+    @VisibleForTesting
+    static final String SECURITY_WARN_DIALOG_TAG = "SecurityWarnDialog";
+    private static final String KEY_INPUT_METHOD_INFO = "INPUT_METHOD_INFO";
+    private final InputMethodManager mInputMethodManager;
+    private final DevicePolicyManager mDevicePolicyManager;
+    private final PackageManager mPackageManager;
+    private final ConfirmationDialogFragment.ConfirmListener mDirectBootWarnConfirmListener =
+            args -> {
+                InputMethodInfo inputMethodInfo = args.getParcelable(KEY_INPUT_METHOD_INFO);
+                InputMethodUtil.enableInputMethod(getContext().getContentResolver(),
+                        inputMethodInfo);
+                refreshUi();
+            };
+    private final ConfirmationDialogFragment.RejectListener mRejectListener = args ->
+            refreshUi();
+    private final ConfirmationDialogFragment.ConfirmListener mSecurityWarnDialogConfirmListener =
+            args -> {
+                InputMethodInfo inputMethodInfo = args.getParcelable(KEY_INPUT_METHOD_INFO);
+                // The user confirmed to enable a 3rd party IME, but we might need to prompt if
+                // it's not
+                // Direct Boot aware.
+                if (inputMethodInfo.getServiceInfo().directBootAware) {
+                    InputMethodUtil.enableInputMethod(getContext().getContentResolver(),
+                            inputMethodInfo);
+                    refreshUi();
+                } else {
+                    showDirectBootWarnDialog(inputMethodInfo);
+                }
+            };
 
     public KeyboardManagementPreferenceController(Context context, String preferenceKey,
             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
         super(context, preferenceKey, fragmentController, uxRestrictions);
+        mPackageManager = context.getPackageManager();
+        mDevicePolicyManager =
+                (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        mInputMethodManager =
+                (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+    }
+
+    @Override
+    protected void onCreateInternal() {
+        super.onCreateInternal();
+
+        ConfirmationDialogFragment dialogFragment = (ConfirmationDialogFragment)
+                getFragmentController().findDialogByTag(DIRECT_BOOT_WARN_DIALOG_TAG);
+        ConfirmationDialogFragment.resetListeners(dialogFragment,
+                mDirectBootWarnConfirmListener,
+                mRejectListener);
+
+        dialogFragment = (ConfirmationDialogFragment) getFragmentController()
+                .findDialogByTag(SECURITY_WARN_DIALOG_TAG);
+        ConfirmationDialogFragment.resetListeners(dialogFragment,
+                mSecurityWarnDialogConfirmListener,
+                mRejectListener);
     }
 
     @Override
@@ -39,8 +107,122 @@
     }
 
     @Override
-    protected void onCreateInternal() {
-        // TODO: create preference for each available keyboard and add those preferences to the
-        //  preference group.
+    protected void updateState(PreferenceGroup preferenceGroup) {
+        List<String> permittedInputMethods = mDevicePolicyManager
+                .getPermittedInputMethodsForCurrentUser();
+        Set<String> permittedInputMethodsSet = permittedInputMethods == null ? null : new HashSet<>(
+                permittedInputMethods);
+
+        preferenceGroup.removeAll();
+
+        List<InputMethodInfo> inputMethodInfos = mInputMethodManager.getInputMethodList();
+        if (inputMethodInfos == null || inputMethodInfos.size() == 0) {
+            return;
+        }
+
+        Collections.sort(inputMethodInfos, Comparator.comparing(
+                (InputMethodInfo a) -> InputMethodUtil.getPackageLabel(mPackageManager, a))
+                .thenComparing((InputMethodInfo a) -> InputMethodUtil.getSummaryString(getContext(),
+                        mInputMethodManager, a)));
+
+        for (InputMethodInfo inputMethodInfo : inputMethodInfos) {
+            if (!isInputMethodAllowedByOrganization(permittedInputMethodsSet, inputMethodInfo)) {
+                continue;
+            }
+
+            Preference preference = createSwitchPreference(inputMethodInfo);
+
+            preference.setEnabled(!isOnlyEnabledDefaultInputMethod(inputMethodInfo));
+
+            preferenceGroup.addPreference(preference);
+        }
+    }
+
+    private boolean isInputMethodAllowedByOrganization(Set<String> permittedList,
+            InputMethodInfo inputMethodInfo) {
+        // permittedList is null means that all input methods are allowed.
+        return (permittedList == null) || permittedList.contains(inputMethodInfo.getPackageName());
+    }
+
+    /**
+     * Check if given input method is the only enabled input method that can be a default system
+     * input method.
+     *
+     * @return {@code true} if input method is the only input method that can be a default system
+     * input method.
+     */
+    private boolean isOnlyEnabledDefaultInputMethod(InputMethodInfo inputMethodInfo) {
+        if (!inputMethodInfo.isDefault(getContext())) {
+            return false;
+        }
+
+        List<InputMethodInfo> inputMethodInfos = mInputMethodManager.getEnabledInputMethodList();
+
+        for (InputMethodInfo imi : inputMethodInfos) {
+            if (!imi.isDefault(getContext())) {
+                continue;
+            }
+
+            if (!imi.getId().equals(inputMethodInfo.getId())) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Create a SwitchPreference to enable/disable an input method.
+     *
+     * @return {@code SwitchPreference} which allows a user to enable/disable an input method.
+     */
+    private SwitchPreference createSwitchPreference(InputMethodInfo inputMethodInfo) {
+        SwitchPreference switchPreference = new SwitchPreference(getContext());
+        switchPreference.setKey(String.valueOf(inputMethodInfo.getId()));
+        switchPreference.setIcon(InputMethodUtil.getPackageIcon(mPackageManager, inputMethodInfo));
+        switchPreference.setTitle(InputMethodUtil.getPackageLabel(mPackageManager,
+                inputMethodInfo));
+        switchPreference.setChecked(InputMethodUtil.isInputMethodEnabled(getContext()
+                .getContentResolver(), inputMethodInfo));
+        switchPreference.setSummary(InputMethodUtil.getSummaryString(getContext(),
+                mInputMethodManager, inputMethodInfo));
+
+        switchPreference.setOnPreferenceChangeListener((switchPref, newValue) -> {
+            boolean enable = (boolean) newValue;
+            if (enable) {
+                showSecurityWarnDialog(inputMethodInfo);
+            } else {
+                InputMethodUtil.disableInputMethod(getContext(), mInputMethodManager,
+                        inputMethodInfo);
+                refreshUi();
+            }
+            return false;
+        });
+        return switchPreference;
+    }
+
+    private void showDirectBootWarnDialog(InputMethodInfo inputMethodInfo) {
+        ConfirmationDialogFragment dialog = new ConfirmationDialogFragment.Builder(getContext())
+                .setMessage(getContext().getString(R.string.direct_boot_unaware_dialog_message_car))
+                .setPositiveButton(android.R.string.ok, mDirectBootWarnConfirmListener)
+                .setNegativeButton(android.R.string.cancel, mRejectListener)
+                .addArgumentParcelable(KEY_INPUT_METHOD_INFO, inputMethodInfo)
+                .build();
+
+        getFragmentController().showDialog(dialog, DIRECT_BOOT_WARN_DIALOG_TAG);
+    }
+
+    private void showSecurityWarnDialog(InputMethodInfo inputMethodInfo) {
+        CharSequence label = inputMethodInfo.loadLabel(mPackageManager);
+
+        ConfirmationDialogFragment dialog = new ConfirmationDialogFragment.Builder(getContext())
+                .setTitle(android.R.string.dialog_alert_title)
+                .setMessage(getContext().getString(R.string.ime_security_warning, label))
+                .setPositiveButton(android.R.string.ok, mSecurityWarnDialogConfirmListener)
+                .setNegativeButton(android.R.string.cancel, mRejectListener)
+                .addArgumentParcelable(KEY_INPUT_METHOD_INFO, inputMethodInfo)
+                .build();
+
+        getFragmentController().showDialog(dialog, SECURITY_WARN_DIALOG_TAG);
     }
 }
diff --git a/tests/robotests/src/com/android/car/settings/inputmethod/EnabledKeyboardPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/inputmethod/EnabledKeyboardPreferenceControllerTest.java
index 57b4d9c..8cc7aad 100644
--- a/tests/robotests/src/com/android/car/settings/inputmethod/EnabledKeyboardPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/car/settings/inputmethod/EnabledKeyboardPreferenceControllerTest.java
@@ -57,6 +57,7 @@
 @Config(shadows = {ShadowInputMethodManager.class, ShadowDevicePolicyManager.class})
 public class EnabledKeyboardPreferenceControllerTest {
     private static final String DUMMY_LABEL = "dummy label";
+    private static final String DUMMY_ID = "dummy id";
     private static final String DUMMY_SETTINGS_ACTIVITY = "dummy settings activity";
     private static final String DUMMY_PACKAGE_NAME = "dummy package name";
     private static final String ALLOWED_PACKAGE_NAME = "allowed package name";
@@ -218,6 +219,7 @@
             PackageManager packageManager, String packageName) {
         InputMethodInfo mockInfo = mock(InputMethodInfo.class);
         when(mockInfo.getPackageName()).thenReturn(packageName);
+        when(mockInfo.getId()).thenReturn(DUMMY_ID);
         when(mockInfo.loadLabel(packageManager)).thenReturn(DUMMY_LABEL);
         when(mockInfo.getServiceInfo()).thenReturn(new ServiceInfo());
         when(mockInfo.getSettingsActivity()).thenReturn(DUMMY_SETTINGS_ACTIVITY);
diff --git a/tests/robotests/src/com/android/car/settings/inputmethod/InputMethodUtilTest.java b/tests/robotests/src/com/android/car/settings/inputmethod/InputMethodUtilTest.java
index 2e995ad..2067089 100644
--- a/tests/robotests/src/com/android/car/settings/inputmethod/InputMethodUtilTest.java
+++ b/tests/robotests/src/com/android/car/settings/inputmethod/InputMethodUtilTest.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
+import android.provider.Settings;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
@@ -43,7 +44,11 @@
 import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 @RunWith(CarSettingsRobolectricTestRunner.class)
 public class InputMethodUtilTest {
@@ -52,8 +57,19 @@
     private static final String DUMMY_SETTINGS_ACTIVITY = "dummy settings activity";
     private static final String SUBTYPES_STRING =
             "English (United States), German (Belgium), and Occitan (France)";
-
+    private static final String DUMMY_ENABLED_INPUT_METHODS =
+            "com.google.android.googlequicksearchbox/com.google.android.voicesearch.ime"
+                    + ".VoiceInputMethodService:com.google.android.apps.automotive.inputmethod/"
+                    + ".InputMethodService";
+    private static final String DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT =
+            "com.google.android.apps.automotive.inputmethod/.InputMethodService";
+    private static final String DUMMY_ENABLED_INPUT_METHOD_ID =
+            "com.google.android.googlequicksearchbox/com.google.android.voicesearch.ime"
+                    + ".VoiceInputMethodService";
+    private static final String DUMMY_DISABLED_INPUT_METHOD_ID = "disabled input method id";
     private Context mContext;
+    private List<InputMethodInfo> mDummyEnabledInputMethodsListAllDefaultable;
+    private List<InputMethodInfo> mDummyEnabledInputMethodsListOneDefaultable;
 
     @Mock
     private PackageManager mPackageManager;
@@ -62,6 +78,197 @@
     @Mock
     private Drawable mIcon;
 
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = RuntimeEnvironment.application;
+
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS, DUMMY_ENABLED_INPUT_METHODS);
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.DEFAULT_INPUT_METHOD, DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+
+        mDummyEnabledInputMethodsListOneDefaultable = Arrays
+                .stream(DUMMY_ENABLED_INPUT_METHODS.split(String.valueOf(InputMethodUtil
+                        .INPUT_METHOD_DELIMITER))).collect(Collectors.toList()).stream().map(
+                            result -> {
+                                InputMethodInfo info = createMockInputMethodInfo(
+                                        mPackageManager, DUMMY_PACKAGE_NAME);
+                                when(info.getId()).thenReturn(result);
+                                when(info.isDefault(mContext)).thenReturn(result.equals(
+                                        DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT));
+                                return info;
+                            }).collect(Collectors.toList());
+        mDummyEnabledInputMethodsListAllDefaultable = Arrays
+                .stream(DUMMY_ENABLED_INPUT_METHODS.split(String.valueOf(InputMethodUtil
+                        .INPUT_METHOD_DELIMITER))).collect(Collectors.toList()).stream().map(
+                                result -> {
+                                    InputMethodInfo info = createMockInputMethodInfo(
+                                            mPackageManager, DUMMY_PACKAGE_NAME);
+                                    when(info.getId()).thenReturn(result);
+                                    when(info.isDefault(mContext)).thenReturn(true);
+                                    return info;
+                                }).collect(Collectors.toList());
+    }
+
+    @Test
+    public void getPackageIcon_hasApplicationIcon() throws NameNotFoundException {
+        InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
+                mInputMethodManager, DUMMY_PACKAGE_NAME);
+        when(mPackageManager.getApplicationIcon(eq(info.getPackageName()))).thenReturn(mIcon);
+        assertThat(InputMethodUtil.getPackageIcon(mPackageManager, info)).isEqualTo(mIcon);
+    }
+
+    @Test
+    public void getPackageIcon_noApplicationIcon() throws NameNotFoundException {
+        InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
+                mInputMethodManager, DUMMY_PACKAGE_NAME);
+        when(mPackageManager.getApplicationIcon(DUMMY_PACKAGE_NAME)).thenThrow(
+                new NameNotFoundException());
+        assertThat(InputMethodUtil.getPackageIcon(mPackageManager, info)).isEqualTo(
+                InputMethodUtil.NO_ICON);
+    }
+
+    @Test
+    public void getPackageLabel() {
+        InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
+                mInputMethodManager, DUMMY_PACKAGE_NAME);
+        assertThat(InputMethodUtil.getPackageLabel(mPackageManager, info)).isEqualTo(
+                DUMMY_LABEL);
+    }
+
+    @Test
+    public void getSummaryString() {
+        InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
+                mInputMethodManager, DUMMY_PACKAGE_NAME);
+        assertThat(InputMethodUtil.getSummaryString(mContext, mInputMethodManager, info)).isEqualTo(
+                SUBTYPES_STRING);
+    }
+
+    @Test
+    public void isInputMethodEnabled_isDisabled_returnsFalse() {
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_DISABLED_INPUT_METHOD_ID);
+
+        assertThat(InputMethodUtil.isInputMethodEnabled(mContext.getContentResolver(), info))
+                .isFalse();
+    }
+
+    @Test
+    public void isInputMethodEnabled_isEnabled_returnsTrue() {
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+
+        assertThat(InputMethodUtil.isInputMethodEnabled(mContext.getContentResolver(), info))
+                .isTrue();
+    }
+
+    @Test
+    public void enableInputMethod_alreadyEnabled_remainsUnchanged() {
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+
+        InputMethodUtil.enableInputMethod(mContext.getContentResolver(), info);
+
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(DUMMY_ENABLED_INPUT_METHODS);
+    }
+
+    @Test
+    public void enableInputMethod_noEnabledInputMethods_addsIME() {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS, "");
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+
+        InputMethodUtil.enableInputMethod(mContext.getContentResolver(), info);
+
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(
+                DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+    }
+
+    @Test
+    public void enableInputMethod_someEnabledInputMethods_addsIME() {
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_DISABLED_INPUT_METHOD_ID);
+
+        InputMethodUtil.enableInputMethod(mContext.getContentResolver(), info);
+
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(
+                DUMMY_ENABLED_INPUT_METHODS + ":"
+                        + DUMMY_DISABLED_INPUT_METHOD_ID);
+    }
+
+    @Test
+    public void disableInputMethod_notEnabled_remainsUnchanged() {
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_DISABLED_INPUT_METHOD_ID);
+        when(mInputMethodManager.getEnabledInputMethodList())
+                .thenReturn(mDummyEnabledInputMethodsListAllDefaultable);
+
+        InputMethodUtil.disableInputMethod(mContext, mInputMethodManager, info);
+
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(DUMMY_ENABLED_INPUT_METHODS);
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.DEFAULT_INPUT_METHOD)).isEqualTo(
+                DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+    }
+
+    @Test
+    public void disableInputMethod_notDefault_removesIMEWhileDefaultRemainsSame() {
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID);
+        when(mInputMethodManager.getEnabledInputMethodList())
+                .thenReturn(mDummyEnabledInputMethodsListAllDefaultable);
+
+        InputMethodUtil.disableInputMethod(mContext, mInputMethodManager, info);
+
+        assertThat(splitConcatenatedIdsIntoSet(Settings.Secure.getString(mContext
+                .getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS))).isEqualTo(
+                splitConcatenatedIdsIntoSet(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT));
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.DEFAULT_INPUT_METHOD)).isEqualTo(
+                DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+    }
+
+    @Test
+    public void disableInputMethod_twoDefaultableIMEsEnabled_removesIMEAndChangesDefault() {
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+        when(mInputMethodManager.getEnabledInputMethodList())
+                .thenReturn(mDummyEnabledInputMethodsListAllDefaultable);
+
+        InputMethodUtil.disableInputMethod(mContext, mInputMethodManager, info);
+
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(
+                DUMMY_ENABLED_INPUT_METHOD_ID);
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.DEFAULT_INPUT_METHOD)).isEqualTo(
+                DUMMY_ENABLED_INPUT_METHOD_ID);
+    }
+
+    @Test
+    public void disableInputMethod_isDefaultWithNoOtherDefaultableEnabled_remainsUnchanged() {
+        InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
+        when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+        when(mInputMethodManager.getEnabledInputMethodList())
+                .thenReturn(mDummyEnabledInputMethodsListOneDefaultable);
+
+        InputMethodUtil.disableInputMethod(mContext, mInputMethodManager, info);
+
+        assertThat(splitConcatenatedIdsIntoSet(Settings.Secure.getString(mContext
+                .getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS))).isEqualTo(
+                splitConcatenatedIdsIntoSet(DUMMY_ENABLED_INPUT_METHODS));
+        assertThat(Settings.Secure.getString(mContext.getContentResolver(),
+                Settings.Secure.DEFAULT_INPUT_METHOD)).isEqualTo(
+                DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
+    }
+
     private static InputMethodInfo createMockInputMethodInfoWithSubtypes(
             PackageManager packageManager, InputMethodManager inputMethodManager,
             String packageName) {
@@ -69,7 +276,6 @@
         List<InputMethodSubtype> subtypes = createSubtypes();
         when(inputMethodManager.getEnabledInputMethodSubtypeList(
                 eq(mockInfo), anyBoolean())).thenReturn(subtypes);
-
         return mockInfo;
     }
 
@@ -96,43 +302,18 @@
                 .setIsAuxiliary(false).setIsAsciiCapable(true).build();
     }
 
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-    }
+    private Set<String> splitConcatenatedIdsIntoSet(String ids) {
+        Set<String> result = new HashSet<>();
 
-    @Test
-    public void testGetPackageIcon_hasApplicationIcon() throws NameNotFoundException {
-        InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
-                mInputMethodManager, DUMMY_PACKAGE_NAME);
-        when(mPackageManager.getApplicationIcon(eq(info.getPackageName()))).thenReturn(mIcon);
-        assertThat(InputMethodUtil.getPackageIcon(mPackageManager, info)).isEqualTo(mIcon);
-    }
+        if (ids == null || ids.isEmpty()) {
+            return result;
+        }
 
-    @Test
-    public void testGetPackageIcon_noApplicationIcon() throws NameNotFoundException {
-        InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
-                mInputMethodManager, DUMMY_PACKAGE_NAME);
-        when(mPackageManager.getApplicationIcon(DUMMY_PACKAGE_NAME)).thenThrow(
-                new NameNotFoundException());
-        assertThat(InputMethodUtil.getPackageIcon(mPackageManager, info)).isEqualTo(
-                InputMethodUtil.NO_ICON);
-    }
+        InputMethodUtil.sInputMethodSplitter.setString(ids);
+        while (InputMethodUtil.sInputMethodSplitter.hasNext()) {
+            result.add(InputMethodUtil.sInputMethodSplitter.next());
+        }
 
-    @Test
-    public void testGetPackageLabel() {
-        InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
-                mInputMethodManager, DUMMY_PACKAGE_NAME);
-        assertThat(InputMethodUtil.getPackageLabel(mPackageManager, info)).isEqualTo(
-                DUMMY_LABEL);
-    }
-
-    @Test
-    public void testGetSummaryString() {
-        InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
-                mInputMethodManager, DUMMY_PACKAGE_NAME);
-        assertThat(InputMethodUtil.getSummaryString(mContext, mInputMethodManager, info)).isEqualTo(
-                SUBTYPES_STRING);
+        return result;
     }
 }
diff --git a/tests/robotests/src/com/android/car/settings/inputmethod/KeyboardManagementPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/inputmethod/KeyboardManagementPreferenceControllerTest.java
new file mode 100644
index 0000000..0bc50ef
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/inputmethod/KeyboardManagementPreferenceControllerTest.java
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.settings.inputmethod;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.SwitchPreference;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.common.ConfirmationDialogFragment;
+import com.android.car.settings.common.LogicalPreferenceGroup;
+import com.android.car.settings.common.PreferenceControllerTestHelper;
+import com.android.car.settings.testutils.ShadowDevicePolicyManager;
+import com.android.car.settings.testutils.ShadowInputMethodManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowInputMethodManager.class, ShadowDevicePolicyManager.class})
+public class KeyboardManagementPreferenceControllerTest {
+    private static final String DUMMY_LABEL = "dummy label";
+    private static final String DUMMY_SETTINGS_ACTIVITY = "dummy settings activity";
+    private static final String DUMMY_PACKAGE_NAME = "dummy package name";
+    private static final String DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE =
+            "dummy id defaultable direct boot aware";
+    private static final String DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE =
+            "dummy id defaultable not direct boot aware";
+    private static final String DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE =
+            "dummy id not defaultable direct boot aware";
+    private static final String DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE =
+            "dummy id not defaultable not direct boot aware";
+    private static final String DISALLOWED_PACKAGE_NAME = "disallowed package name";
+    private static final String ALLOWED_PACKAGE_NAME = "allowed package name";
+    private List<String> mPermittedList;
+    private PreferenceControllerTestHelper<KeyboardManagementPreferenceController>
+            mControllerHelper;
+    private PreferenceGroup mPreferenceGroup;
+    private Context mContext;
+    private InputMethodManager mInputMethodManager;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+
+        mPreferenceGroup = new LogicalPreferenceGroup(mContext);
+        mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
+                KeyboardManagementPreferenceController.class, mPreferenceGroup);
+        mInputMethodManager = (InputMethodManager) mContext.getSystemService(Context
+                .INPUT_METHOD_SERVICE);
+
+        mPermittedList = new ArrayList<>();
+        mPermittedList.add(DUMMY_PACKAGE_NAME);
+        mPermittedList.add(ALLOWED_PACKAGE_NAME);
+        mControllerHelper.markState(Lifecycle.State.CREATED);
+    }
+
+    @Test
+    public void refreshUi_permitAllInputMethods_preferenceCountIs4() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+        getShadowInputMethodManager(mContext).setInputMethodList(infos);
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
+
+        mControllerHelper.getController().refreshUi();
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(4);
+    }
+
+    @Test
+    public void refreshUi_multiplteAllowedImeByOrganization_allPreferencesVisible() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(
+                mPermittedList);
+        List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+        getShadowInputMethodManager(mContext).setInputMethodList(infos);
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
+
+        mControllerHelper.getController().refreshUi();
+
+        for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
+            assertThat(mPreferenceGroup.getPreference(i).isVisible()).isTrue();
+        }
+    }
+
+    @Test
+    public void refreshUi_multipleEnabledInputMethods_allPreferencesEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(
+                mPermittedList);
+        List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+        getShadowInputMethodManager(mContext).setInputMethodList(infos);
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
+
+        mControllerHelper.getController().refreshUi();
+
+        for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
+            assertThat(mPreferenceGroup.getPreference(i).isEnabled()).isTrue();
+        }
+    }
+
+    @Test
+    public void refreshUi_multipleEnabledInputMethods_allPreferencesChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(
+                mPermittedList);
+        List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+        getShadowInputMethodManager(mContext).setInputMethodList(infos);
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
+
+        mControllerHelper.getController().refreshUi();
+
+        for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
+            assertThat(((SwitchPreference) mPreferenceGroup.getPreference(i)).isChecked())
+                    .isTrue();
+        }
+    }
+
+    @Test
+    public void refreshUi_disallowedByOrganization_noPreferencesShown() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(
+                mPermittedList);
+        List<InputMethodInfo> infos = createInputMethodInfoList(DISALLOWED_PACKAGE_NAME,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+        getShadowInputMethodManager(mContext).setInputMethodList(infos);
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
+
+        mControllerHelper.getController().refreshUi();
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
+    }
+
+    @Test
+    public void refreshUi_verifyPreferenceIcon() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+        getShadowInputMethodManager(mContext).setInputMethodList(infos);
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
+
+        mControllerHelper.getController().refreshUi();
+
+        Preference preference = mPreferenceGroup.getPreference(0);
+        assertThat(preference.getIcon()).isEqualTo(
+                InputMethodUtil.getPackageIcon(mContext.getPackageManager(), infos.get(0)));
+    }
+
+    @Test
+    public void refreshUi_verifyPreferenceTitle() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+        getShadowInputMethodManager(mContext).setInputMethodList(infos);
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
+
+        mControllerHelper.getController().refreshUi();
+
+        Preference preference = mPreferenceGroup.getPreference(0);
+        assertThat(preference.getTitle()).isEqualTo(
+                InputMethodUtil.getPackageLabel(mContext.getPackageManager(), infos.get(0)));
+    }
+
+    @Test
+    public void refreshUi_verifyPreferenceSummary() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        List<InputMethodInfo> infos = createInputMethodInfoList(ALLOWED_PACKAGE_NAME,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+        getShadowInputMethodManager(mContext).setInputMethodList(infos);
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(infos);
+
+        mControllerHelper.getController().refreshUi();
+
+        InputMethodManager inputMethodManager =
+                (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+        Preference preference = mPreferenceGroup.getPreference(0);
+        assertThat(preference.getSummary()).isEqualTo(
+                InputMethodUtil.getSummaryString(mContext, inputMethodManager, infos.get(0)));
+    }
+
+    @Test
+    public void refreshUi_oneInputMethod_noneEnabled_oneInputMethodPreferenceInView() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
+    }
+
+    @Test
+    public void refreshUi_oneInputMethod_noneEnabled_preferenceEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
+    }
+
+    @Test
+    public void refreshUi_oneInputMethod_noneEnabled_preferenceNotChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
+                .isFalse();
+    }
+
+    @Test
+    public void performClick_toggleTrue_securityDialogShown() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                any(ConfirmationDialogFragment.class),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+    }
+
+    @Test
+    public void performClick_toggleTrue_showSecurityDialog_positive_noOtherPreferenceAdded() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
+        assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
+    }
+
+    @Test
+    public void performClick_toggleTrue_showSecurityDialog_positive_preferenceChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
+                .isTrue();
+    }
+
+    @Test
+    public void performClick_toggleTrue_showSecurityDialog_positive_preferenceEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
+    }
+
+    @Test
+    public void performClick_toggleTrue_showSecurityDialog_positive_inputMethodEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        assertThat(mInputMethodManager.getEnabledInputMethodList().get(0).getId())
+                .isEqualTo(DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
+    }
+
+    @Test
+    public void performClick_toggleTrue_showSecurityDialog_negative_noOtherPreferenceAdded() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
+        assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
+                DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE);
+    }
+
+    @Test
+    public void performClick_toggleTrue_showSecurityDialog_negative_preferenceEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+        assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
+    }
+
+    @Test
+    public void performClick_toggleTrue_showSecurityDialog_negative_inputMethodDisabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+        assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
+                .isFalse();
+    }
+
+    @Test
+    public void performClick_toggleTrue_directBootWarningShown() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                any(ConfirmationDialogFragment.class),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+    }
+
+    @Test
+    public void performClick_toggleTrue_showDirectBootDialog_positive_noOtherPreferenceAdded() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+        dialogFragment = bootDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
+        assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+    }
+
+    @Test
+    public void performClick_toggleTrue_showDirectBootDialog_positive_preferenceChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+        dialogFragment = bootDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
+                .isTrue();
+    }
+
+    @Test
+    public void performClick_toggleTrue_showDirectBootDialog_positive_preferenceEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+        dialogFragment = bootDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
+    }
+
+    @Test
+    public void performClick_toggleTrue_showDirectBootDialog_positive_inputMethodEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+        dialogFragment = bootDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        assertThat(mInputMethodManager.getEnabledInputMethodList().get(0).getId())
+                .isEqualTo(DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+    }
+
+    @Test
+    public void performClick_toggleTrue_showDirectBootDialog_negative_noOtherPreferenceAdded() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+        dialogFragment = bootDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
+        assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+    }
+
+    @Test
+    public void performClick_toggleTrue_showDirectBootDialog_negative_preferenceNotChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+        dialogFragment = bootDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+
+        assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
+                .isFalse();
+    }
+
+    @Test
+    public void performClick_toggleTrue_showDirectBootDialog_negative_preferenceEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+        dialogFragment = bootDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+        assertThat(mPreferenceGroup.getPreference(0).isEnabled()).isTrue();
+    }
+
+    @Test
+    public void performClick_toggleTrue_showDirectBootDialog_negative_inputMethodDisabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(new ArrayList<>());
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> securityDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(
+                securityDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = securityDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        ArgumentCaptor<ConfirmationDialogFragment> bootDialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(bootDialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.DIRECT_BOOT_WARN_DIALOG_TAG));
+        dialogFragment = bootDialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+        assertThat(mInputMethodManager.getEnabledInputMethodList().size())
+                .isEqualTo(0);
+    }
+
+    @Test
+    public void performClick_toggleFalse_noOtherPreferenceAdded() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
+        assertThat(mPreferenceGroup.getPreference(0).getKey()).isEqualTo(
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE);
+    }
+
+    @Test
+    public void performClick_toggleFalse_preferenceNotChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        assertThat(((SwitchPreference) mPreferenceGroup.getPreference(0)).isChecked())
+                .isFalse();
+    }
+
+    @Test
+    public void performClick_toggleFalse_preferenceEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        assertThat((mPreferenceGroup.getPreference(0)).isEnabled())
+                .isTrue();
+    }
+
+    @Test
+    public void performClick_toggleFalse_inputMethodDisabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+
+        mControllerHelper.getController().refreshUi();
+
+        mPreferenceGroup.getPreference(0).performClick();
+
+        assertThat(mInputMethodManager.getEnabledInputMethodList().size())
+                .isEqualTo(0);
+    }
+
+    @Test
+    public void performClick_toggleFalse_twoDefaultable_notClickDefaultablePreferenceDisabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+
+        mControllerHelper.getController().refreshUi();
+
+        getPreferenceFromGroupByKey(mPreferenceGroup, DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE)
+                .performClick();
+
+        assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE).isEnabled()).isFalse();
+    }
+
+    @Test
+    public void performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+
+        mControllerHelper.getController().refreshUi();
+
+        getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
+
+        assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).isEnabled()).isTrue();
+    }
+
+    @Test
+    public void performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+
+        mControllerHelper.getController().refreshUi();
+
+        getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
+
+        assertThat(getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE).isEnabled()).isTrue();
+    }
+
+    @Test
+    public void performClick_toggleFalse_twoDefaultable_clickedDefaultablePreferenceNotChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+
+        mControllerHelper.getController().refreshUi();
+
+        getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
+
+        assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE)).isChecked()).isFalse();
+    }
+
+    @Test
+    public void performClick_toggleFalse_twoDefaultable_notClickedDefaultablePreferenceChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+
+        mControllerHelper.getController().refreshUi();
+
+        getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
+
+        assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)).isChecked()).isTrue();
+    }
+
+    @Test
+    public void performClick_toggleFalse_twoDefaultable_nonDefaultablePreferenceChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+
+        mControllerHelper.getController().refreshUi();
+
+        getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
+
+        assertThat(((SwitchPreference) getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)).isChecked()).isTrue();
+    }
+
+    @Test
+    public void performClick_toggleTrue_twoDefaultable_allPreferencesEnabled() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+
+        mControllerHelper.getController().refreshUi();
+
+        getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
+            assertThat(mPreferenceGroup.getPreference(i).isEnabled()).isTrue();
+        }
+    }
+
+    @Test
+    public void performClick_toggleTrue_twoDefaultable_allPreferencesChecked() {
+        getShadowDevicePolicyManager(mContext).setPermittedInputMethodsForCurrentUser(null);
+        getShadowInputMethodManager(mContext).setInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE, DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE)
+        );
+        getShadowInputMethodManager(mContext).setEnabledInputMethodList(createInputMethodInfoList(
+                ALLOWED_PACKAGE_NAME, DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE,
+                DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE));
+
+        mControllerHelper.getController().refreshUi();
+
+        getPreferenceFromGroupByKey(mPreferenceGroup,
+                DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE).performClick();
+
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mControllerHelper.getMockFragmentController()).showDialog(dialogCaptor.capture(),
+                eq(KeyboardManagementPreferenceController.SECURITY_WARN_DIALOG_TAG));
+        ConfirmationDialogFragment dialogFragment = dialogCaptor.getValue();
+
+        dialogFragment.onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+        for (int i = 0; i < mPreferenceGroup.getPreferenceCount(); i++) {
+            assertThat(((SwitchPreference) mPreferenceGroup.getPreference(i)).isChecked())
+                    .isTrue();
+        }
+    }
+
+    private static InputMethodInfo createMockInputMethodInfo(
+            Context context, PackageManager packageManager,
+            ShadowInputMethodManager inputMethodManager, String packageName, String id,
+            boolean isDefaultable, boolean directBootAware) {
+        ServiceInfo mockServiceInfo = mock(ServiceInfo.class);
+        mockServiceInfo.directBootAware = directBootAware;
+
+        InputMethodInfo mockInfo = mock(InputMethodInfo.class);
+        when(mockInfo.getPackageName()).thenReturn(packageName);
+        when(mockInfo.loadLabel(packageManager)).thenReturn(DUMMY_LABEL);
+        when(mockInfo.getServiceInfo()).thenReturn(mockServiceInfo);
+        when(mockInfo.getSettingsActivity()).thenReturn(DUMMY_SETTINGS_ACTIVITY);
+        when(mockInfo.getId()).thenReturn(id);
+        when(mockInfo.isDefault(context)).thenReturn(isDefaultable);
+        List<InputMethodSubtype> subtypes = createSubtypes();
+        inputMethodManager.setEnabledInputMethodSubtypeList(subtypes);
+        return mockInfo;
+    }
+
+    private static Preference getPreferenceFromGroupByKey(PreferenceGroup prefGroup, String key) {
+        for (int i = 0; i < prefGroup.getPreferenceCount(); i++) {
+            Preference pref = prefGroup.getPreference(i);
+            if (pref.getKey().equals(key)) {
+                return pref;
+            }
+        }
+        return null;
+    }
+
+    private static List<InputMethodSubtype> createSubtypes() {
+        List<InputMethodSubtype> subtypes = new ArrayList<>();
+        subtypes.add(createSubtype(1, "en_US"));
+        subtypes.add(createSubtype(2, "de_BE"));
+        subtypes.add(createSubtype(3, "oc-FR"));
+        return subtypes;
+    }
+
+    private static InputMethodSubtype createSubtype(int id, String locale) {
+        return new InputMethodSubtype.InputMethodSubtypeBuilder().setSubtypeId(id)
+                .setSubtypeLocale(locale).setIsAuxiliary(false).setIsAsciiCapable(true).build();
+    }
+
+    private static ShadowInputMethodManager getShadowInputMethodManager(Context context) {
+        return Shadow.extract(context.getSystemService(Context.INPUT_METHOD_SERVICE));
+    }
+
+    private static ShadowDevicePolicyManager getShadowDevicePolicyManager(Context context) {
+        return Shadow.extract(context.getSystemService(Context.DEVICE_POLICY_SERVICE));
+    }
+
+    private List<InputMethodInfo> createInputMethodInfoList(String packageName, String... ids) {
+        List<InputMethodInfo> infos = new ArrayList<>();
+        PackageManager packageManager = mContext.getPackageManager();
+        List<String> idsList = Arrays.asList(ids);
+        idsList.forEach(id -> {
+            boolean defaultable;
+            boolean directBootAware;
+            switch (id) {
+                case DUMMY_ID_DEFAULTABLE_DIRECT_BOOT_AWARE:
+                    defaultable = true;
+                    directBootAware = true;
+                    break;
+                case DUMMY_ID_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE:
+                    defaultable = true;
+                    directBootAware = false;
+                    break;
+                case DUMMY_ID_NOT_DEFAULTABLE_DIRECT_BOOT_AWARE:
+                    defaultable = false;
+                    directBootAware = true;
+                    break;
+                default: //case DUMMY_ID_NOT_DEFAULTABLE_NOT_DIRECT_BOOT_AWARE:
+                    defaultable = false;
+                    directBootAware = false;
+                    break;
+            }
+            infos.add(createMockInputMethodInfo(mContext, packageManager,
+                    getShadowInputMethodManager(mContext), packageName, id, defaultable,
+                    directBootAware));
+        });
+        return infos;
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/testutils/ShadowInputMethodManager.java b/tests/robotests/src/com/android/car/settings/testutils/ShadowInputMethodManager.java
index fc2e6e4..f6ccbc0 100644
--- a/tests/robotests/src/com/android/car/settings/testutils/ShadowInputMethodManager.java
+++ b/tests/robotests/src/com/android/car/settings/testutils/ShadowInputMethodManager.java
@@ -16,29 +16,56 @@
 
 package com.android.car.settings.testutils;
 
+import android.provider.Settings;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 
 import androidx.annotation.Nullable;
 
+import com.android.car.settings.inputmethod.InputMethodUtil;
+
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @Implements(value = InputMethodManager.class)
 public class ShadowInputMethodManager extends org.robolectric.shadows.ShadowInputMethodManager {
-    private List<InputMethodInfo> mEnabledInputMethodList;
+    private List<InputMethodInfo> mInputMethodList;
+    private Map<String, InputMethodInfo> mInputMethodMap;
     private List<InputMethodSubtype> mInputMethodSubtypes;
 
-    public void setEnabledInputMethodList(@Nullable List<InputMethodInfo> list) {
-        mEnabledInputMethodList = list;
+    public void setEnabledInputMethodList(@Nullable List<InputMethodInfo> inputMethodInfos) {
+        String concatenatedInputMethodIds = createInputMethodIdString(inputMethodInfos.stream().map(
+                imi -> imi.getId()).collect(Collectors.toList()).toArray(
+                new String[inputMethodInfos.size()]));
+        Settings.Secure.putString(RuntimeEnvironment.application.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS, concatenatedInputMethodIds);
+        addInputMethodInfosToMap(inputMethodInfos);
     }
 
     @Implementation
-    public List<InputMethodInfo> getEnabledInputMethodList() {
-        return mEnabledInputMethodList;
+    protected List<InputMethodInfo> getEnabledInputMethodList() {
+        List<InputMethodInfo> enabledInputMethodList = new ArrayList<>();
+
+        String inputMethodIdString = Settings.Secure.getString(
+                RuntimeEnvironment.application.getContentResolver(),
+                Settings.Secure.ENABLED_INPUT_METHODS);
+        if (inputMethodIdString == null || inputMethodIdString.isEmpty()) {
+            return enabledInputMethodList;
+        }
+
+        InputMethodUtil.sInputMethodSplitter.setString(inputMethodIdString);
+        while (InputMethodUtil.sInputMethodSplitter.hasNext()) {
+            enabledInputMethodList.add(mInputMethodMap.get(InputMethodUtil.sInputMethodSplitter
+                    .next()));
+        }
+        return enabledInputMethodList;
     }
 
     public void setEnabledInputMethodSubtypeList(List<InputMethodSubtype> list) {
@@ -46,8 +73,51 @@
     }
 
     @Implementation
-    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
+    protected List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
             boolean allowsImplicitlySelectedSubtypes) {
         return mInputMethodSubtypes;
     }
+
+    public void setInputMethodList(List<InputMethodInfo> inputMethodInfos) {
+        mInputMethodList = inputMethodInfos;
+        if (inputMethodInfos == null) {
+            return;
+        }
+
+        addInputMethodInfosToMap(inputMethodInfos);
+    }
+
+    @Implementation
+    protected List<InputMethodInfo> getInputMethodList() {
+        return mInputMethodList;
+    }
+
+    private static String createInputMethodIdString(String... ids) {
+        int size = ids == null ? 0 : ids.length;
+
+        if (size == 1) {
+            return ids[0];
+        }
+
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < size; i++) {
+            builder.append(ids[i]);
+            if (i != size - 1) {
+                builder.append(InputMethodUtil.INPUT_METHOD_DELIMITER);
+            }
+        }
+        return builder.toString();
+    }
+
+    private void addInputMethodInfosToMap(List<InputMethodInfo> inputMethodInfos) {
+        if (mInputMethodMap == null || mInputMethodMap.size() == 0) {
+            mInputMethodMap = inputMethodInfos.stream().collect(Collectors.toMap(
+                    InputMethodInfo::getId, imi -> imi));
+            return;
+        }
+
+        inputMethodInfos.forEach(imi -> {
+            mInputMethodMap.put(imi.getId(), imi);
+        });
+    }
 }