Reenable pre-N style hard keyboard layout settings
This CL logically reverts Settings app changes for Bug 25752812, which aimed to improve UX by tightly integrating physical keyboard layout with input method subtype. What went wrong is that the concept of input method subtype is not widely accepted by the ecosystem actually. Until we figoure out any other better way here, let's revert back to the good old way that enables users to specify multiple keyboard layouts per physical keyboard device, not one layout per one input method subtype. Note that we cannot simply revert the CL that originally introduced the new flow [1] because it was indeed a huge CL that also touched IME settings, which we want to continue using. In that sense, this CL is a kind of re-implementation of the previous style on top of the recent language settings flow. Note also that a fix [2] fox Bug 25062009 was also ported from previous InputMethodAndLanguageSetting to KeyboardLayoutPickerFragment. [1]: I728d7ee185827ed328c16cb7abce244557a26518976bb3f459
[2]: I4483dfc89afc8d148b2cfa7c6a5f66d2a02f712a17b6319884
Fix: 66498367 Test: make -j RunSettingsRoboTests Test: Manually done with two Bluetooth keyboards Change-Id: I7a2ed6dd39dcd8207d3d94e12cd01d5d67ba4bb5
This commit is contained in:
@@ -4177,10 +4177,6 @@
|
|||||||
<string name="keyboard_shortcuts_helper">Keyboard shortcuts helper</string>
|
<string name="keyboard_shortcuts_helper">Keyboard shortcuts helper</string>
|
||||||
<!-- Summary text for the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=100] -->
|
<!-- Summary text for the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=100] -->
|
||||||
<string name="keyboard_shortcuts_helper_summary">Display available shortcuts</string>
|
<string name="keyboard_shortcuts_helper_summary">Display available shortcuts</string>
|
||||||
<!--
|
|
||||||
Format string for a physical device in the form: InputMethodSubtype - InputMethodEditor.
|
|
||||||
e.g. English (US) - X Keyboard -->
|
|
||||||
<string name="physical_device_title" translatable="false"><xliff:g id="input_method_editor" example="X Keyboard">%1$s</xliff:g> - <xliff:g id="input_method_subtype" example="English (US)">%2$s</xliff:g></string>
|
|
||||||
|
|
||||||
<!-- Summary text for keyboards when no layout has been selected. [CHAR LIMIT=35] -->
|
<!-- Summary text for keyboards when no layout has been selected. [CHAR LIMIT=35] -->
|
||||||
<string name="default_keyboard_layout">Default</string>
|
<string name="default_keyboard_layout">Default</string>
|
||||||
|
@@ -16,43 +16,31 @@
|
|||||||
|
|
||||||
package com.android.settings.inputmethod;
|
package com.android.settings.inputmethod;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.content.Context;
|
||||||
import android.app.Activity;
|
|
||||||
import android.hardware.input.InputDeviceIdentifier;
|
import android.hardware.input.InputDeviceIdentifier;
|
||||||
import android.hardware.input.InputManager;
|
import android.hardware.input.InputManager;
|
||||||
import android.hardware.input.InputManager.InputDeviceListener;
|
import android.hardware.input.InputManager.InputDeviceListener;
|
||||||
import android.hardware.input.KeyboardLayout;
|
import android.hardware.input.KeyboardLayout;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.preference.CheckBoxPreference;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.PreferenceScreen;
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
|
|
||||||
import android.view.inputmethod.InputMethodInfo;
|
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
|
||||||
import com.android.internal.logging.MetricsLogger;
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.internal.util.Preconditions;
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
import com.android.settings.inputmethod.PhysicalKeyboardFragment.KeyboardInfoPreference;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragment
|
public class KeyboardLayoutPickerFragment extends SettingsPreferenceFragment
|
||||||
implements InputDeviceListener {
|
implements InputDeviceListener {
|
||||||
|
|
||||||
private InputDeviceIdentifier mInputDeviceIdentifier;
|
private InputDeviceIdentifier mInputDeviceIdentifier;
|
||||||
private int mInputDeviceId = -1;
|
private int mInputDeviceId = -1;
|
||||||
private InputManager mIm;
|
private InputManager mIm;
|
||||||
private InputMethodInfo mImi;
|
|
||||||
@Nullable
|
|
||||||
private InputMethodSubtype mSubtype;
|
|
||||||
private KeyboardLayout[] mKeyboardLayouts;
|
private KeyboardLayout[] mKeyboardLayouts;
|
||||||
private Map<Preference, KeyboardLayout> mPreferenceMap = new HashMap<>();
|
private HashMap<CheckBoxPreference, KeyboardLayout> mPreferenceMap = new HashMap<>();
|
||||||
|
|
||||||
// TODO: Make these constants public API for b/25752827
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intent extra: The input device descriptor of the keyboard whose keyboard
|
* Intent extra: The input device descriptor of the keyboard whose keyboard
|
||||||
@@ -60,16 +48,6 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme
|
|||||||
*/
|
*/
|
||||||
public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
|
public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
|
||||||
|
|
||||||
/**
|
|
||||||
* Intent extra: The associated {@link InputMethodInfo}.
|
|
||||||
*/
|
|
||||||
public static final String EXTRA_INPUT_METHOD_INFO = "input_method_info";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intent extra: The associated {@link InputMethodSubtype}.
|
|
||||||
*/
|
|
||||||
public static final String EXTRA_INPUT_METHOD_SUBTYPE = "input_method_subtype";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
return MetricsEvent.INPUTMETHOD_KEYBOARD;
|
return MetricsEvent.INPUTMETHOD_KEYBOARD;
|
||||||
@@ -78,18 +56,14 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
Activity activity = Preconditions.checkNotNull(getActivity());
|
|
||||||
|
|
||||||
mInputDeviceIdentifier = activity.getIntent().getParcelableExtra(
|
mInputDeviceIdentifier = getActivity().getIntent().getParcelableExtra(
|
||||||
EXTRA_INPUT_DEVICE_IDENTIFIER);
|
EXTRA_INPUT_DEVICE_IDENTIFIER);
|
||||||
mImi = activity.getIntent().getParcelableExtra(EXTRA_INPUT_METHOD_INFO);
|
if (mInputDeviceIdentifier == null) {
|
||||||
mSubtype = activity.getIntent().getParcelableExtra(EXTRA_INPUT_METHOD_SUBTYPE);
|
getActivity().finish();
|
||||||
|
|
||||||
if (mInputDeviceIdentifier == null || mImi == null) {
|
|
||||||
activity.finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mIm = activity.getSystemService(InputManager.class);
|
mIm = (InputManager) getSystemService(Context.INPUT_SERVICE);
|
||||||
mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier);
|
mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier);
|
||||||
Arrays.sort(mKeyboardLayouts);
|
Arrays.sort(mKeyboardLayouts);
|
||||||
setPreferenceScreen(createPreferenceHierarchy());
|
setPreferenceScreen(createPreferenceHierarchy());
|
||||||
@@ -108,6 +82,8 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mInputDeviceId = inputDevice.getId();
|
mInputDeviceId = inputDevice.getId();
|
||||||
|
|
||||||
|
updateCheckedState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -120,21 +96,34 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceTreeClick(Preference preference) {
|
public boolean onPreferenceTreeClick(Preference preference) {
|
||||||
KeyboardLayout layout = mPreferenceMap.get(preference);
|
if (preference instanceof CheckBoxPreference) {
|
||||||
|
CheckBoxPreference checkboxPref = (CheckBoxPreference)preference;
|
||||||
|
KeyboardLayout layout = mPreferenceMap.get(checkboxPref);
|
||||||
if (layout != null) {
|
if (layout != null) {
|
||||||
mIm.setKeyboardLayoutForInputDevice(mInputDeviceIdentifier, mImi, mSubtype,
|
boolean checked = checkboxPref.isChecked();
|
||||||
|
if (checked) {
|
||||||
|
mIm.addKeyboardLayoutForInputDevice(mInputDeviceIdentifier,
|
||||||
layout.getDescriptor());
|
layout.getDescriptor());
|
||||||
getActivity().finish();
|
} else {
|
||||||
|
mIm.removeKeyboardLayoutForInputDevice(mInputDeviceIdentifier,
|
||||||
|
layout.getDescriptor());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return super.onPreferenceTreeClick(preference);
|
return super.onPreferenceTreeClick(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInputDeviceAdded(int deviceId) {}
|
public void onInputDeviceAdded(int deviceId) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInputDeviceChanged(int deviceId) {}
|
public void onInputDeviceChanged(int deviceId) {
|
||||||
|
if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
|
||||||
|
updateCheckedState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInputDeviceRemoved(int deviceId) {
|
public void onInputDeviceRemoved(int deviceId) {
|
||||||
@@ -147,14 +136,23 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme
|
|||||||
PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity());
|
PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity());
|
||||||
|
|
||||||
for (KeyboardLayout layout : mKeyboardLayouts) {
|
for (KeyboardLayout layout : mKeyboardLayouts) {
|
||||||
Preference pref = new Preference(getPrefContext());
|
CheckBoxPreference pref = new CheckBoxPreference(getPrefContext());
|
||||||
pref.setTitle(layout.getLabel());
|
pref.setTitle(layout.getLabel());
|
||||||
pref.setSummary(layout.getCollection());
|
pref.setSummary(layout.getCollection());
|
||||||
root.addPreference(pref);
|
root.addPreference(pref);
|
||||||
mPreferenceMap.put(pref, layout);
|
mPreferenceMap.put(pref, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
root.setTitle(KeyboardInfoPreference.getDisplayName(getContext(), mImi, mSubtype));
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateCheckedState() {
|
||||||
|
String[] enabledKeyboardLayouts = mIm.getEnabledKeyboardLayoutsForInputDevice(
|
||||||
|
mInputDeviceIdentifier);
|
||||||
|
Arrays.sort(enabledKeyboardLayouts);
|
||||||
|
|
||||||
|
for (Map.Entry<CheckBoxPreference, KeyboardLayout> entry : mPreferenceMap.entrySet()) {
|
||||||
|
entry.getKey().setChecked(Arrays.binarySearch(enabledKeyboardLayouts,
|
||||||
|
entry.getValue().getDescriptor()) >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,11 +19,8 @@ package com.android.settings.inputmethod;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.LoaderManager;
|
|
||||||
import android.content.AsyncTaskLoader;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.Loader;
|
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.hardware.input.InputDeviceIdentifier;
|
import android.hardware.input.InputDeviceIdentifier;
|
||||||
import android.hardware.input.InputManager;
|
import android.hardware.input.InputManager;
|
||||||
@@ -40,9 +37,6 @@ import android.support.v7.preference.PreferenceCategory;
|
|||||||
import android.support.v7.preference.PreferenceScreen;
|
import android.support.v7.preference.PreferenceScreen;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.inputmethod.InputMethodInfo;
|
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
|
||||||
|
|
||||||
import com.android.internal.inputmethod.InputMethodUtils;
|
import com.android.internal.inputmethod.InputMethodUtils;
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
@@ -52,33 +46,25 @@ import com.android.settings.Settings;
|
|||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.search.Indexable;
|
import com.android.settings.search.Indexable;
|
||||||
import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
||||||
implements InputManager.InputDeviceListener, Indexable {
|
implements InputManager.InputDeviceListener,
|
||||||
|
KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener, Indexable {
|
||||||
|
|
||||||
private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category";
|
private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category";
|
||||||
private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch";
|
private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch";
|
||||||
private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper";
|
private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper";
|
||||||
private static final String IM_SUBTYPE_MODE_KEYBOARD = "keyboard";
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final List<HardKeyboardDeviceInfo> mLastHardKeyboards = new ArrayList<>();
|
private final ArrayList<HardKeyboardDeviceInfo> mLastHardKeyboards = new ArrayList<>();
|
||||||
@NonNull
|
|
||||||
private final List<KeyboardInfoPreference> mTempKeyboardInfoList = new ArrayList<>();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final HashSet<Integer> mLoaderIDs = new HashSet<>();
|
|
||||||
private int mNextLoaderId = 0;
|
|
||||||
|
|
||||||
private InputManager mIm;
|
private InputManager mIm;
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -88,6 +74,8 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|||||||
@NonNull
|
@NonNull
|
||||||
private InputMethodUtils.InputMethodSettings mSettings;
|
private InputMethodUtils.InputMethodSettings mSettings;
|
||||||
|
|
||||||
|
private Intent mIntentWaitingForResult;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(Bundle bundle, String s) {
|
public void onCreatePreferences(Bundle bundle, String s) {
|
||||||
Activity activity = Preconditions.checkNotNull(getActivity());
|
Activity activity = Preconditions.checkNotNull(getActivity());
|
||||||
@@ -118,9 +106,8 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
clearLoader();
|
|
||||||
mLastHardKeyboards.clear();
|
mLastHardKeyboards.clear();
|
||||||
updateHardKeyboards();
|
scheduleUpdateHardKeyboards();
|
||||||
mIm.registerInputDeviceListener(this, null);
|
mIm.registerInputDeviceListener(this, null);
|
||||||
mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(
|
mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(
|
||||||
mShowVirtualKeyboardSwitchPreferenceChangeListener);
|
mShowVirtualKeyboardSwitchPreferenceChangeListener);
|
||||||
@@ -130,67 +117,25 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
clearLoader();
|
|
||||||
mLastHardKeyboards.clear();
|
mLastHardKeyboards.clear();
|
||||||
mIm.unregisterInputDeviceListener(this);
|
mIm.unregisterInputDeviceListener(this);
|
||||||
mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(null);
|
mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(null);
|
||||||
unregisterShowVirtualKeyboardSettingsObserver();
|
unregisterShowVirtualKeyboardSettingsObserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLoadFinishedInternal(
|
|
||||||
final int loaderId, @NonNull final List<Keyboards> keyboardsList) {
|
|
||||||
if (!mLoaderIDs.remove(loaderId)) {
|
|
||||||
// Already destroyed loader. Ignore.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(keyboardsList);
|
|
||||||
final PreferenceScreen preferenceScreen = getPreferenceScreen();
|
|
||||||
preferenceScreen.removeAll();
|
|
||||||
for (Keyboards keyboards : keyboardsList) {
|
|
||||||
final PreferenceCategory category = new PreferenceCategory(getPrefContext(), null);
|
|
||||||
category.setTitle(keyboards.mDeviceInfo.mDeviceName);
|
|
||||||
category.setOrder(0);
|
|
||||||
preferenceScreen.addPreference(category);
|
|
||||||
for (Keyboards.KeyboardInfo info : keyboards.mKeyboardInfoList) {
|
|
||||||
mTempKeyboardInfoList.clear();
|
|
||||||
final InputMethodInfo imi = info.mImi;
|
|
||||||
final InputMethodSubtype imSubtype = info.mImSubtype;
|
|
||||||
if (imi != null) {
|
|
||||||
KeyboardInfoPreference pref =
|
|
||||||
new KeyboardInfoPreference(getPrefContext(), info);
|
|
||||||
pref.setOnPreferenceClickListener(preference -> {
|
|
||||||
showKeyboardLayoutScreen(
|
|
||||||
keyboards.mDeviceInfo.mDeviceIdentifier, imi, imSubtype);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
mTempKeyboardInfoList.add(pref);
|
|
||||||
Collections.sort(mTempKeyboardInfoList);
|
|
||||||
}
|
|
||||||
for (KeyboardInfoPreference pref : mTempKeyboardInfoList) {
|
|
||||||
category.addPreference(pref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mTempKeyboardInfoList.clear();
|
|
||||||
mKeyboardAssistanceCategory.setOrder(1);
|
|
||||||
preferenceScreen.addPreference(mKeyboardAssistanceCategory);
|
|
||||||
updateShowVirtualKeyboardSwitch();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInputDeviceAdded(int deviceId) {
|
public void onInputDeviceAdded(int deviceId) {
|
||||||
updateHardKeyboards();
|
scheduleUpdateHardKeyboards();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInputDeviceRemoved(int deviceId) {
|
public void onInputDeviceRemoved(int deviceId) {
|
||||||
updateHardKeyboards();
|
scheduleUpdateHardKeyboards();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInputDeviceChanged(int deviceId) {
|
public void onInputDeviceChanged(int deviceId) {
|
||||||
updateHardKeyboards();
|
scheduleUpdateHardKeyboards();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -198,50 +143,57 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|||||||
return MetricsEvent.PHYSICAL_KEYBOARDS;
|
return MetricsEvent.PHYSICAL_KEYBOARDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
private void scheduleUpdateHardKeyboards() {
|
||||||
public static List<HardKeyboardDeviceInfo> getHardKeyboards() {
|
final Context context = getContext();
|
||||||
final List<HardKeyboardDeviceInfo> keyboards = new ArrayList<>();
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
final int[] devicesIds = InputDevice.getDeviceIds();
|
final List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboards(context);
|
||||||
for (int deviceId : devicesIds) {
|
ThreadUtils.postOnMainThread(() -> updateHardKeyboards(newHardKeyboards));
|
||||||
final InputDevice device = InputDevice.getDevice(deviceId);
|
});
|
||||||
if (device != null && !device.isVirtual() && device.isFullKeyboard()) {
|
|
||||||
keyboards.add(new HardKeyboardDeviceInfo(device.getName(), device.getIdentifier()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keyboards;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateHardKeyboards() {
|
private void updateHardKeyboards(@NonNull List<HardKeyboardDeviceInfo> newHardKeyboards) {
|
||||||
final List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboards();
|
if (Objects.equals(mLastHardKeyboards, newHardKeyboards)) {
|
||||||
if (!Objects.equals(newHardKeyboards, mLastHardKeyboards)) {
|
// Nothing has changed. Ignore.
|
||||||
clearLoader();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(yukawa): Maybe we should follow the style used in ConnectedDeviceDashboardFragment.
|
||||||
|
|
||||||
mLastHardKeyboards.clear();
|
mLastHardKeyboards.clear();
|
||||||
mLastHardKeyboards.addAll(newHardKeyboards);
|
mLastHardKeyboards.addAll(newHardKeyboards);
|
||||||
mLoaderIDs.add(mNextLoaderId);
|
|
||||||
getLoaderManager().initLoader(mNextLoaderId, null,
|
final PreferenceScreen preferenceScreen = getPreferenceScreen();
|
||||||
new Callbacks(getContext(), this, mLastHardKeyboards));
|
preferenceScreen.removeAll();
|
||||||
++mNextLoaderId;
|
final PreferenceCategory category = new PreferenceCategory(getPrefContext());
|
||||||
}
|
category.setTitle(R.string.builtin_keyboard_settings_title);
|
||||||
|
category.setOrder(0);
|
||||||
|
preferenceScreen.addPreference(category);
|
||||||
|
|
||||||
|
for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
|
||||||
|
// TODO(yukawa): Consider using com.android.settings.widget.GearPreference
|
||||||
|
final Preference pref = new Preference(getPrefContext());
|
||||||
|
pref.setTitle(hardKeyboardDeviceInfo.mDeviceName);
|
||||||
|
pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
|
||||||
|
pref.setOnPreferenceClickListener(preference -> {
|
||||||
|
showKeyboardLayoutDialog(hardKeyboardDeviceInfo.mDeviceIdentifier);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
category.addPreference(pref);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showKeyboardLayoutScreen(
|
mKeyboardAssistanceCategory.setOrder(1);
|
||||||
@NonNull InputDeviceIdentifier inputDeviceIdentifier,
|
preferenceScreen.addPreference(mKeyboardAssistanceCategory);
|
||||||
@NonNull InputMethodInfo imi,
|
updateShowVirtualKeyboardSwitch();
|
||||||
@Nullable InputMethodSubtype imSubtype) {
|
|
||||||
final Intent intent = new Intent(Intent.ACTION_MAIN);
|
|
||||||
intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class);
|
|
||||||
intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
|
|
||||||
inputDeviceIdentifier);
|
|
||||||
intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_METHOD_INFO, imi);
|
|
||||||
intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_METHOD_SUBTYPE, imSubtype);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearLoader() {
|
private void showKeyboardLayoutDialog(InputDeviceIdentifier inputDeviceIdentifier) {
|
||||||
for (final int loaderId : mLoaderIDs) {
|
KeyboardLayoutDialogFragment fragment = (KeyboardLayoutDialogFragment)
|
||||||
getLoaderManager().destroyLoader(loaderId);
|
getFragmentManager().findFragmentByTag("keyboardLayout");
|
||||||
|
if (fragment == null) {
|
||||||
|
fragment = new KeyboardLayoutDialogFragment(inputDeviceIdentifier);
|
||||||
|
fragment.setTargetFragment(this, 0);
|
||||||
|
fragment.show(getActivity().getFragmentManager(), "keyboardLayout");
|
||||||
}
|
}
|
||||||
mLoaderIDs.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerShowVirtualKeyboardSettingsObserver() {
|
private void registerShowVirtualKeyboardSettingsObserver() {
|
||||||
@@ -282,102 +234,75 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final class Callbacks implements LoaderManager.LoaderCallbacks<List<Keyboards>> {
|
@Override
|
||||||
@NonNull
|
public void onSetupKeyboardLayouts(InputDeviceIdentifier inputDeviceIdentifier) {
|
||||||
final Context mContext;
|
final Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||||
@NonNull
|
intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class);
|
||||||
final PhysicalKeyboardFragment mPhysicalKeyboardFragment;
|
intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
|
||||||
@NonNull
|
inputDeviceIdentifier);
|
||||||
final List<HardKeyboardDeviceInfo> mHardKeyboards;
|
mIntentWaitingForResult = intent;
|
||||||
|
startActivityForResult(intent, 0);
|
||||||
public Callbacks(
|
|
||||||
@NonNull Context context,
|
|
||||||
@NonNull PhysicalKeyboardFragment physicalKeyboardFragment,
|
|
||||||
@NonNull List<HardKeyboardDeviceInfo> hardKeyboards) {
|
|
||||||
mContext = context;
|
|
||||||
mPhysicalKeyboardFragment = physicalKeyboardFragment;
|
|
||||||
mHardKeyboards = hardKeyboards;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<List<Keyboards>> onCreateLoader(int id, Bundle args) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
return new KeyboardLayoutLoader(mContext, mHardKeyboards);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (mIntentWaitingForResult != null) {
|
||||||
public void onLoadFinished(Loader<List<Keyboards>> loader, List<Keyboards> data) {
|
InputDeviceIdentifier inputDeviceIdentifier = mIntentWaitingForResult
|
||||||
mPhysicalKeyboardFragment.onLoadFinishedInternal(loader.getId(), data);
|
.getParcelableExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER);
|
||||||
}
|
mIntentWaitingForResult = null;
|
||||||
|
showKeyboardLayoutDialog(inputDeviceIdentifier);
|
||||||
@Override
|
|
||||||
public void onLoaderReset(Loader<List<Keyboards>> loader) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class KeyboardLayoutLoader extends AsyncTaskLoader<List<Keyboards>> {
|
private static String getLayoutLabel(@NonNull InputDevice device,
|
||||||
|
@NonNull Context context, @NonNull InputManager im) {
|
||||||
|
final String currentLayoutDesc =
|
||||||
|
im.getCurrentKeyboardLayoutForInputDevice(device.getIdentifier());
|
||||||
|
if (currentLayoutDesc == null) {
|
||||||
|
return context.getString(R.string.keyboard_layout_default_label);
|
||||||
|
}
|
||||||
|
final KeyboardLayout currentLayout = im.getKeyboardLayout(currentLayoutDesc);
|
||||||
|
if (currentLayout == null) {
|
||||||
|
return context.getString(R.string.keyboard_layout_default_label);
|
||||||
|
}
|
||||||
|
// If current layout is specified but the layout is null, just return an empty string
|
||||||
|
// instead of falling back to R.string.keyboard_layout_default_label.
|
||||||
|
return TextUtils.emptyIfNull(currentLayout.getLabel());
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final List<HardKeyboardDeviceInfo> mHardKeyboards;
|
static List<HardKeyboardDeviceInfo> getHardKeyboards(@NonNull Context context) {
|
||||||
|
final List<HardKeyboardDeviceInfo> keyboards = new ArrayList<>();
|
||||||
public KeyboardLayoutLoader(
|
final InputManager im = context.getSystemService(InputManager.class);
|
||||||
@NonNull Context context,
|
if (im == null) {
|
||||||
@NonNull List<HardKeyboardDeviceInfo> hardKeyboards) {
|
return new ArrayList<>();
|
||||||
super(context);
|
|
||||||
mHardKeyboards = Preconditions.checkNotNull(hardKeyboards);
|
|
||||||
}
|
}
|
||||||
|
for (int deviceId : InputDevice.getDeviceIds()) {
|
||||||
private Keyboards loadInBackground(HardKeyboardDeviceInfo deviceInfo) {
|
final InputDevice device = InputDevice.getDevice(deviceId);
|
||||||
final ArrayList<Keyboards.KeyboardInfo> keyboardInfoList = new ArrayList<>();
|
if (device == null || device.isVirtual() || !device.isFullKeyboard()) {
|
||||||
final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
|
|
||||||
final InputManager im = getContext().getSystemService(InputManager.class);
|
|
||||||
if (imm != null && im != null) {
|
|
||||||
for (InputMethodInfo imi : imm.getEnabledInputMethodList()) {
|
|
||||||
final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(
|
|
||||||
imi, true /* allowsImplicitlySelectedSubtypes */);
|
|
||||||
if (subtypes.isEmpty()) {
|
|
||||||
// Here we use null to indicate that this IME has no subtype.
|
|
||||||
final InputMethodSubtype nullSubtype = null;
|
|
||||||
final KeyboardLayout layout = im.getKeyboardLayoutForInputDevice(
|
|
||||||
deviceInfo.mDeviceIdentifier, imi, nullSubtype);
|
|
||||||
keyboardInfoList.add(new Keyboards.KeyboardInfo(imi, nullSubtype, layout));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
keyboards.add(new HardKeyboardDeviceInfo(
|
||||||
// If the IME supports subtypes, we pick up "keyboard" subtypes only.
|
device.getName(), device.getIdentifier(), getLayoutLabel(device, context, im)));
|
||||||
final int N = subtypes.size();
|
|
||||||
for (int i = 0; i < N; ++i) {
|
|
||||||
final InputMethodSubtype subtype = subtypes.get(i);
|
|
||||||
if (!IM_SUBTYPE_MODE_KEYBOARD.equalsIgnoreCase(subtype.getMode())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final KeyboardLayout layout = im.getKeyboardLayoutForInputDevice(
|
|
||||||
deviceInfo.mDeviceIdentifier, imi, subtype);
|
|
||||||
keyboardInfoList.add(new Keyboards.KeyboardInfo(imi, subtype, layout));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Keyboards(deviceInfo, keyboardInfoList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// We intentionally don't reuse Comparator because Collator may not be thread-safe.
|
||||||
public List<Keyboards> loadInBackground() {
|
final Collator collator = Collator.getInstance();
|
||||||
List<Keyboards> keyboardsList = new ArrayList<>(mHardKeyboards.size());
|
keyboards.sort((a, b) -> {
|
||||||
for (HardKeyboardDeviceInfo deviceInfo : mHardKeyboards) {
|
int result = collator.compare(a.mDeviceName, b.mDeviceName);
|
||||||
keyboardsList.add(loadInBackground(deviceInfo));
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return keyboardsList;
|
result = a.mDeviceIdentifier.getDescriptor().compareTo(
|
||||||
}
|
b.mDeviceIdentifier.getDescriptor());
|
||||||
|
if (result != 0) {
|
||||||
@Override
|
return result;
|
||||||
protected void onStartLoading() {
|
|
||||||
super.onStartLoading();
|
|
||||||
forceLoad();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStopLoading() {
|
|
||||||
super.onStopLoading();
|
|
||||||
cancelLoad();
|
|
||||||
}
|
}
|
||||||
|
return collator.compare(a.mLayoutLabel, b.mLayoutLabel);
|
||||||
|
});
|
||||||
|
return keyboards;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class HardKeyboardDeviceInfo {
|
public static final class HardKeyboardDeviceInfo {
|
||||||
@@ -385,12 +310,16 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|||||||
public final String mDeviceName;
|
public final String mDeviceName;
|
||||||
@NonNull
|
@NonNull
|
||||||
public final InputDeviceIdentifier mDeviceIdentifier;
|
public final InputDeviceIdentifier mDeviceIdentifier;
|
||||||
|
@NonNull
|
||||||
|
public final String mLayoutLabel;
|
||||||
|
|
||||||
public HardKeyboardDeviceInfo(
|
public HardKeyboardDeviceInfo(
|
||||||
@Nullable final String deviceName,
|
@Nullable String deviceName,
|
||||||
@NonNull final InputDeviceIdentifier deviceIdentifier) {
|
@NonNull InputDeviceIdentifier deviceIdentifier,
|
||||||
mDeviceName = deviceName != null ? deviceName : "";
|
@NonNull String layoutLabel) {
|
||||||
|
mDeviceName = TextUtils.emptyIfNull(deviceName);
|
||||||
mDeviceIdentifier = deviceIdentifier;
|
mDeviceIdentifier = deviceIdentifier;
|
||||||
|
mLayoutLabel = layoutLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -404,14 +333,10 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|||||||
if (!TextUtils.equals(mDeviceName, that.mDeviceName)) {
|
if (!TextUtils.equals(mDeviceName, that.mDeviceName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mDeviceIdentifier.getVendorId() != that.mDeviceIdentifier.getVendorId()) {
|
if (!Objects.equals(mDeviceIdentifier, that.mDeviceIdentifier)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mDeviceIdentifier.getProductId() != that.mDeviceIdentifier.getProductId()) {
|
if (!TextUtils.equals(mLayoutLabel, that.mLayoutLabel)) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!TextUtils.equals(mDeviceIdentifier.getDescriptor(),
|
|
||||||
that.mDeviceIdentifier.getDescriptor())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,121 +344,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Keyboards implements Comparable<Keyboards> {
|
|
||||||
@NonNull
|
|
||||||
public final HardKeyboardDeviceInfo mDeviceInfo;
|
|
||||||
@NonNull
|
|
||||||
public final ArrayList<KeyboardInfo> mKeyboardInfoList;
|
|
||||||
@NonNull
|
|
||||||
public final Collator mCollator = Collator.getInstance();
|
|
||||||
|
|
||||||
public Keyboards(
|
|
||||||
@NonNull final HardKeyboardDeviceInfo deviceInfo,
|
|
||||||
@NonNull final ArrayList<KeyboardInfo> keyboardInfoList) {
|
|
||||||
mDeviceInfo = deviceInfo;
|
|
||||||
mKeyboardInfoList = keyboardInfoList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(@NonNull Keyboards another) {
|
|
||||||
return mCollator.compare(mDeviceInfo.mDeviceName, another.mDeviceInfo.mDeviceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class KeyboardInfo {
|
|
||||||
@NonNull
|
|
||||||
public final InputMethodInfo mImi;
|
|
||||||
@Nullable
|
|
||||||
public final InputMethodSubtype mImSubtype;
|
|
||||||
@NonNull
|
|
||||||
public final KeyboardLayout mLayout;
|
|
||||||
|
|
||||||
public KeyboardInfo(
|
|
||||||
@NonNull final InputMethodInfo imi,
|
|
||||||
@Nullable final InputMethodSubtype imSubtype,
|
|
||||||
@NonNull final KeyboardLayout layout) {
|
|
||||||
mImi = imi;
|
|
||||||
mImSubtype = imSubtype;
|
|
||||||
mLayout = layout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class KeyboardInfoPreference extends Preference {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final CharSequence mImeName;
|
|
||||||
@Nullable
|
|
||||||
private final CharSequence mImSubtypeName;
|
|
||||||
@NonNull
|
|
||||||
private final Collator collator = Collator.getInstance();
|
|
||||||
|
|
||||||
private KeyboardInfoPreference(
|
|
||||||
@NonNull Context context, @NonNull Keyboards.KeyboardInfo info) {
|
|
||||||
super(context);
|
|
||||||
mImeName = info.mImi.loadLabel(context.getPackageManager());
|
|
||||||
mImSubtypeName = getImSubtypeName(context, info.mImi, info.mImSubtype);
|
|
||||||
setTitle(formatDisplayName(context, mImeName, mImSubtypeName));
|
|
||||||
if (info.mLayout != null) {
|
|
||||||
setSummary(info.mLayout.getLabel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
static CharSequence getDisplayName(
|
|
||||||
@NonNull Context context, @NonNull InputMethodInfo imi,
|
|
||||||
@Nullable InputMethodSubtype imSubtype) {
|
|
||||||
final CharSequence imeName = imi.loadLabel(context.getPackageManager());
|
|
||||||
final CharSequence imSubtypeName = getImSubtypeName(context, imi, imSubtype);
|
|
||||||
return formatDisplayName(context, imeName, imSubtypeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CharSequence formatDisplayName(
|
|
||||||
@NonNull Context context,
|
|
||||||
@NonNull CharSequence imeName, @Nullable CharSequence imSubtypeName) {
|
|
||||||
if (imSubtypeName == null) {
|
|
||||||
return imeName;
|
|
||||||
}
|
|
||||||
return String.format(
|
|
||||||
context.getString(R.string.physical_device_title), imeName, imSubtypeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static CharSequence getImSubtypeName(
|
|
||||||
@NonNull Context context, @NonNull InputMethodInfo imi,
|
|
||||||
@Nullable InputMethodSubtype imSubtype) {
|
|
||||||
if (imSubtype != null) {
|
|
||||||
return InputMethodAndSubtypeUtil.getSubtypeLocaleNameAsSentence(
|
|
||||||
imSubtype, context, imi);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(@NonNull Preference object) {
|
|
||||||
if (!(object instanceof KeyboardInfoPreference)) {
|
|
||||||
return super.compareTo(object);
|
|
||||||
}
|
|
||||||
KeyboardInfoPreference another = (KeyboardInfoPreference) object;
|
|
||||||
int result = compare(mImeName, another.mImeName);
|
|
||||||
if (result == 0) {
|
|
||||||
result = compare(mImSubtypeName, another.mImSubtypeName);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int compare(@Nullable CharSequence lhs, @Nullable CharSequence rhs) {
|
|
||||||
if (!TextUtils.isEmpty(lhs) && !TextUtils.isEmpty(rhs)) {
|
|
||||||
return collator.compare(lhs.toString(), rhs.toString());
|
|
||||||
} else if (TextUtils.isEmpty(lhs) && TextUtils.isEmpty(rhs)) {
|
|
||||||
return 0;
|
|
||||||
} else if (!TextUtils.isEmpty(lhs)) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||||
new BaseSearchIndexProvider() {
|
new BaseSearchIndexProvider() {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -94,7 +94,7 @@ public class PhysicalKeyboardPreferenceController extends AbstractPreferenceCont
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final List<HardKeyboardDeviceInfo> keyboards =
|
final List<HardKeyboardDeviceInfo> keyboards =
|
||||||
PhysicalKeyboardFragment.getHardKeyboards();
|
PhysicalKeyboardFragment.getHardKeyboards(mContext);
|
||||||
if (keyboards.isEmpty()) {
|
if (keyboards.isEmpty()) {
|
||||||
mPreference.setSummary(R.string.disconnected);
|
mPreference.setSummary(R.string.disconnected);
|
||||||
return;
|
return;
|
||||||
|
@@ -55,7 +55,7 @@ public class PhysicalKeyboardPreferenceControllerTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
when(mContext.getSystemService(Context.INPUT_SERVICE)).thenReturn(mIm);
|
when(mContext.getSystemService(InputManager.class)).thenReturn(mIm);
|
||||||
mController = new PhysicalKeyboardPreferenceController(mContext, null /* lifecycle */);
|
mController = new PhysicalKeyboardPreferenceController(mContext, null /* lifecycle */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user