Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f43c358b authored by danielwbhuang's avatar danielwbhuang
Browse files

Integrate UI with APIs for physical keyboard settgins.

Integrate UI with these APIs.
1. getKeyboardLayoutListForInputDevice
2. getKeyboardLayoutForInputDevice
3. setKeyboardLayoutForInputDevice

Demo: go/pk_with_final_api_demo

Bug: 247079681
Test: local test

Change-Id: I5478e2c344a47e692e7c524f8c1e96d9dda52796
parent 9a1247e5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3713,6 +3713,8 @@
    <string name="language_and_input_for_work_category_title">Work profile keyboards &amp; tools</string>
    <!-- Title for the 'Virtual keyboards for work' preference. [CHAR LIMIT=45] -->
    <string name="virtual_keyboards_for_work_title">On-screen keyboard for work</string>
    <!-- Summary text for none selected keyboard default layout -->
    <string name="keyboard_default_layout">Default</string>
    <!-- Title for the button to trigger the 'trackpad settings' page if only connect with a touchpad. [CHAR LIMIT=35] -->
    <string name="trackpad_settings">Touchpad</string>
+1 −4
Original line number Diff line number Diff line
@@ -16,8 +16,5 @@
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:title="@string/physical_keyboard_title">
    <PreferenceCategory
        android:key="enabled_locales_keyboard_layout"
        android:title="@string/enabled_locales_keyboard_layout">
    </PreferenceCategory>

</PreferenceScreen>
 No newline at end of file
+129 −34
Original line number Diff line number Diff line
@@ -20,64 +20,124 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;

import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.inputmethod.NewKeyboardSettingsUtils.KeyboardInfo;

import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
        implements InputManager.InputDeviceListener {

    private static final String TAG = "NewKeyboardLayoutEnabledLocalesFragment";
    private static final String PREF_KEY_ENABLED_LOCALES = "enabled_locales_keyboard_layout";

    static final String EXTRA_KEYBOARD_DEVICE_NAME = "extra_keyboard_device_name";

    private InputManager mIm;
    private InputMethodManager mImm;
    private InputDeviceIdentifier mInputDeviceIdentifier;
    private int mUserId;
    private int mInputDeviceId;
    private Context mContext;
    private Map<String, KeyboardInfo> mKeyboardLanguageLayouts = new HashMap<>();

    @Override
    public void onActivityCreated(final Bundle icicle) {
        super.onActivityCreated(icicle);

        Bundle arguments = getArguments();
        final String title = arguments.getString(EXTRA_KEYBOARD_DEVICE_NAME);
        mInputDeviceIdentifier = arguments.getParcelable(
                KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER);
        final String title =
                arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_DEVICE_NAME);
        mInputDeviceIdentifier =
                arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
        getActivity().setTitle(title);
        final PreferenceCategory category = findPreference(PREF_KEY_ENABLED_LOCALES);

        // TODO(b/252816846): Need APIs to get the available keyboards from Inputmanager.
        // For example: InputMethodManager.getEnabledInputMethodLocales()
        //              InputManager.getKeyboardLayoutForLocale()
        // Hardcode the default value for demo purpose
        String[] keyboardLanguages = {"English (US)", "German (Germany)", "Spanish (Spain)"};
        String[] keyboardLayouts = {"English (US)", "German", "Spanish"};
        for (int i = 0; i < keyboardLanguages.length; i++) {
        updateCheckedState();
    }

    private void updateCheckedState() {
        PreferenceScreen preferenceScreen = getPreferenceScreen();
        preferenceScreen.removeAll();
        List<InputMethodInfo> infoList = mImm.getEnabledInputMethodListAsUser(mUserId);
        for (InputMethodInfo info : infoList) {
            mKeyboardLanguageLayouts.clear();
            List<InputMethodSubtype> subtypes =
                    mImm.getEnabledInputMethodSubtypeList(info, true);
            for (InputMethodSubtype subtype : subtypes) {
                if (subtype.isSuitableForPhysicalKeyboardLayoutMapping()) {
                    mapLanguageWithLayout(info, subtype);
                }
            }
            updatePreferenceLayout(preferenceScreen, info);
        }
    }

    private void mapLanguageWithLayout(InputMethodInfo info, InputMethodSubtype subtype) {
        KeyboardLayout[] keyboardLayouts = getKeyboardLayouts(info, subtype);
        String layout = getKeyboardLayout(info, subtype);
        String language = getLanguage(info, subtype);
        if (layout != null) {
            for (int i = 0; i < keyboardLayouts.length; i++) {
                if (keyboardLayouts[i].getDescriptor().equals(layout)) {
                    KeyboardInfo keyboardInfo = new KeyboardInfo(
                            language,
                            keyboardLayouts[i].getLabel(),
                            info,
                            subtype);
                    mKeyboardLanguageLayouts.put(subtype.getLanguageTag(), keyboardInfo);
                    break;
                }
            }
        } else {
            // if there is no auto-selected layout, we should show "Default"
            KeyboardInfo keyboardInfo = new KeyboardInfo(
                    language,
                    mContext.getString(R.string.keyboard_default_layout),
                    info,
                    subtype);
            mKeyboardLanguageLayouts.put(subtype.getLanguageTag(), keyboardInfo);
        }
    }

    private void updatePreferenceLayout(PreferenceScreen preferenceScreen, InputMethodInfo info) {
        if (mKeyboardLanguageLayouts.isEmpty()) {
            return;
        }
        PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
        preferenceCategory.setTitle(info.loadLabel(mContext.getPackageManager()).toString());
        preferenceCategory.setKey(info.getPackageName());
        preferenceScreen.addPreference(preferenceCategory);
        for (Map.Entry<String, KeyboardInfo> entry : mKeyboardLanguageLayouts.entrySet()) {
            final Preference pref = new Preference(mContext);
            String key = "keyboard_language_label_" + String.valueOf(i);
            String keyboardLanguageTitle = keyboardLanguages[i];
            String keyboardLanguageSummary = keyboardLayouts[i];
            // TODO: Waiting for new API to use a prefix with special number to setKey
            String key = "keyboard_language_" + entry.getKey();
            NewKeyboardSettingsUtils.KeyboardInfo keyboardInfo = entry.getValue();
            pref.setKey(key);
            pref.setTitle(keyboardLanguageTitle);
            pref.setSummary(keyboardLanguageSummary);
            pref.setTitle(keyboardInfo.getLanguage());
            pref.setSummary(keyboardInfo.getLayout());
            pref.setOnPreferenceClickListener(
                    preference -> {
                        showKeyboardLayoutPicker(
                                keyboardLanguageTitle,
                                keyboardLanguageSummary,
                                mInputDeviceIdentifier);
                                keyboardInfo.getLanguage(),
                                keyboardInfo.getLayout(),
                                mInputDeviceIdentifier,
                                mUserId,
                                keyboardInfo.getInputMethodInfo(),
                                keyboardInfo.getInputMethodSubtype());
                        return true;
                    });
            category.addPreference(pref);
            preferenceCategory.addPreference(pref);
        }
    }

@@ -96,7 +156,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
    @Override
    public void onInputDeviceChanged(int deviceId) {
        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
            // TODO(b/252816846): Need APIs to update the available keyboards.
            updateCheckedState();
        }
    }

@@ -105,7 +165,9 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
        super.onCreate(savedInstanceState);
        mContext = getContext();
        mIm = mContext.getSystemService(InputManager.class);
        mImm = mContext.getSystemService(InputMethodManager.class);
        mInputDeviceId = -1;
        mUserId = UserHandle.myUserId();
    }

    @Override
@@ -131,7 +193,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
    @Override
    public void onResume() {
        super.onResume();
        // TODO(b/252816846): Need APIs to get the available keyboards from Inputmanager.
        updateCheckedState();
    }

    @Override
@@ -149,17 +211,50 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
        return R.xml.keyboard_settings_enabled_locales_list;
    }

    private void showKeyboardLayoutPicker(String language, String layout,
            InputDeviceIdentifier inputDeviceIdentifier) {
    private void showKeyboardLayoutPicker(
            String language,
            String layout,
            InputDeviceIdentifier inputDeviceIdentifier,
            int userId,
            InputMethodInfo inputMethodInfo,
            InputMethodSubtype inputMethodSubtype) {
        Bundle arguments = new Bundle();
        arguments.putParcelable(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
                inputDeviceIdentifier);
        arguments.putString(NewKeyboardLayoutPickerFragment.EXTRA_TITLE, language);
        arguments.putString(NewKeyboardLayoutPickerFragment.EXTRA_KEYBOARD_LAYOUT, layout);
        arguments.putParcelable(
                NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER, inputDeviceIdentifier);
        arguments.putParcelable(
                NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO, inputMethodInfo);
        arguments.putParcelable(
                NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE, inputMethodSubtype);
        arguments.putInt(NewKeyboardSettingsUtils.EXTRA_USER_ID, userId);
        arguments.putString(NewKeyboardSettingsUtils.EXTRA_TITLE, language);
        arguments.putString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT, layout);
        new SubSettingLauncher(mContext)
                .setSourceMetricsCategory(getMetricsCategory())
                .setDestination(NewKeyboardLayoutPickerFragment.class.getName())
                .setArguments(arguments)
                .launch();
    }

    private KeyboardLayout[] getKeyboardLayouts(InputMethodInfo info, InputMethodSubtype subtype) {
        return mIm.getKeyboardLayoutListForInputDevice(
                mInputDeviceIdentifier, mUserId, info, subtype);
    }

    private String getKeyboardLayout(InputMethodInfo info, InputMethodSubtype subtype) {
        return mIm.getKeyboardLayoutForInputDevice(
                mInputDeviceIdentifier, mUserId, info, subtype);
    }

    private String getLanguage(InputMethodInfo info, InputMethodSubtype subtype) {
        String language;
        if (subtype.getLanguageTag().isEmpty()) {
            language = subtype.getDisplayName(
                    mContext,
                    info.getPackageName(),
                    info.getServiceInfo().applicationInfo).toString();
        } else {
            language = Locale.forLanguageTag(subtype.getLanguageTag()).getDisplayName();
        }
        return language;
    }
}
+13 −14
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
import android.os.Bundle;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;

import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -28,31 +30,28 @@ public class NewKeyboardLayoutPickerContent extends DashboardFragment {

    private static final String TAG = "KeyboardLayoutPicker";

    static final String EXTRA_TITLE = "keyboard_layout_picker_title";
    static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout";

    /**
     * Intent extra: The input device descriptor of the keyboard whose keyboard
     * layout is to be changed.
     */
    public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        Bundle arguments = getArguments();
        final String title = arguments.getString(EXTRA_TITLE);
        final String layout = arguments.getString(EXTRA_KEYBOARD_LAYOUT);
        final String title = arguments.getString(NewKeyboardSettingsUtils.EXTRA_TITLE);
        final String layout = arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT);
        final int userId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID);
        final InputDeviceIdentifier inputDeviceIdentifier =
                arguments.getParcelable(EXTRA_INPUT_DEVICE_IDENTIFIER);
                arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
        final InputMethodInfo inputMethodInfo =
                arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO);
        final InputMethodSubtype inputMethodSubtype =
                arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE);


        if (inputDeviceIdentifier == null) {
            getActivity().finish();
        }
        getActivity().setTitle(title);
        use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/,
                inputDeviceIdentifier, layout);
        use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/, userId,
                inputDeviceIdentifier, inputMethodInfo, inputMethodSubtype, layout);
    }

    @Override
+28 −21
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout;
import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;

import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
@@ -31,7 +33,6 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@@ -42,7 +43,11 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController

    private Fragment mParent;
    private int mInputDeviceId;
    private int mUserId;
    private InputDeviceIdentifier mInputDeviceIdentifier;
    private InputMethodInfo mInputMethodInfo;
    private InputMethodSubtype mInputMethodSubtype;

    private KeyboardLayout[] mKeyboardLayouts;
    private PreferenceScreen mScreen;
    private String mPreviousSelection;
@@ -55,13 +60,16 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
        mPreferenceMap = new HashMap<>();
    }

    public void initialize(Fragment parent, InputDeviceIdentifier inputDeviceIdentifier,
            String layout) {
        mLayout = layout;
    public void initialize(Fragment parent, int userId, InputDeviceIdentifier inputDeviceIdentifier,
            InputMethodInfo imeInfo, InputMethodSubtype imeSubtype, String layout) {
        mParent = parent;
        mUserId = userId;
        mInputDeviceIdentifier = inputDeviceIdentifier;
        mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier);
        Arrays.sort(mKeyboardLayouts);
        mInputMethodInfo = imeInfo;
        mInputMethodSubtype = imeSubtype;
        mLayout = layout;
        mKeyboardLayouts = mIm.getKeyboardLayoutListForInputDevice(
                inputDeviceIdentifier, userId, imeInfo, imeSubtype);
    }

    @Override
@@ -102,15 +110,12 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
        }

        final KeyboardLayoutPreference pref = (KeyboardLayoutPreference) preference;
        // TODO(b/259530132): Need APIs to update the available keyboards for input device.
        // For example:
        // inputManager.setCurrentKeyboardLayoutForInputDevice(
        //            InputDevice..., Userid..., ImeSubType ..., String keyboardLayoutDescriptor)
        pref.setCheckMark(true);
        if (mPreviousSelection != null && !mPreviousSelection.equals(preference.getKey())) {
            KeyboardLayoutPreference preSelectedPref = mScreen.findPreference(mPreviousSelection);
            pref.setCheckMark(true);
            preSelectedPref.setCheckMark(false);
        }
        setLayout(pref);
        mPreviousSelection = preference.getKey();
        return true;
    }
@@ -129,13 +134,7 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController

    @Override
    public void onInputDeviceChanged(int deviceId) {
        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
            updateCheckedState();
        }
    }

    private void updateCheckedState() {
        // TODO(b/259530132): Need API to update the keyboard language layout list.
        // Do nothing.
    }

    private void createPreferenceHierarchy() {
@@ -143,14 +142,22 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
            final KeyboardLayoutPreference pref;
            if (mLayout.equals(layout.getLabel())) {
                pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), true);
                mPreviousSelection = layout.getLabel();
                mPreviousSelection = layout.getDescriptor();
            } else {
                pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), false);
            }
            // TODO: Waiting for new API to use a prefix with special number to setKey
            pref.setKey(layout.getLabel());
            pref.setKey(layout.getDescriptor());
            mScreen.addPreference(pref);
            mPreferenceMap.put(pref, layout);
        }
    }

    private void setLayout(KeyboardLayoutPreference preference) {
        mIm.setKeyboardLayoutForInputDevice(
                mInputDeviceIdentifier,
                mUserId,
                mInputMethodInfo,
                mInputMethodSubtype,
                mPreferenceMap.get(preference).getDescriptor());
    }
}
Loading