| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.settings.inputmethod; |
| 18 | |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 19 | import android.annotation.NonNull; |
| 20 | import android.annotation.Nullable; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 21 | import android.app.Activity; |
| Fan Zhang | 31b2100 | 2019-01-16 13:49:47 -0800 | [diff] [blame] | 22 | import android.app.settings.SettingsEnums; |
| Abodunrinwa Toki | 5f0b59b | 2016-01-25 23:02:23 +0000 | [diff] [blame] | 23 | import android.content.Context; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 24 | import android.content.Intent; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 25 | import android.database.ContentObserver; |
| 26 | import android.hardware.input.InputDeviceIdentifier; |
| 27 | import android.hardware.input.InputManager; |
| 28 | import android.hardware.input.KeyboardLayout; |
| 29 | import android.os.Bundle; |
| 30 | import android.os.Handler; |
| Yohei Yukawa | 966476b | 2016-06-16 00:02:01 -0700 | [diff] [blame] | 31 | import android.os.UserHandle; |
| Fan Zhang | e3535d9 | 2017-08-02 17:32:43 -0700 | [diff] [blame] | 32 | import android.provider.SearchIndexableResource; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 33 | import android.provider.Settings.Secure; |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 34 | import android.text.TextUtils; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 35 | import android.view.InputDevice; |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 36 | |
| Fan Zhang | 23f8d59 | 2018-08-28 15:11:40 -0700 | [diff] [blame] | 37 | import androidx.preference.Preference; |
| 38 | import androidx.preference.Preference.OnPreferenceChangeListener; |
| 39 | import androidx.preference.PreferenceCategory; |
| 40 | import androidx.preference.PreferenceScreen; |
| 41 | import androidx.preference.SwitchPreference; |
| 42 | |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 43 | import com.android.internal.util.Preconditions; |
| 44 | import com.android.settings.R; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 45 | import com.android.settings.Settings; |
| 46 | import com.android.settings.SettingsPreferenceFragment; |
| Tadashi G. Takaoka | 7bbc632 | 2017-01-10 15:02:22 +0900 | [diff] [blame] | 47 | import com.android.settings.search.BaseSearchIndexProvider; |
| 48 | import com.android.settings.search.Indexable; |
| Tony Mantler | 0fcd6cb | 2018-03-26 15:17:25 -0700 | [diff] [blame] | 49 | import com.android.settingslib.search.SearchIndexable; |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 50 | import com.android.settingslib.utils.ThreadUtils; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 51 | |
| Abodunrinwa Toki | 226e452 | 2016-04-22 17:45:03 +0100 | [diff] [blame] | 52 | import java.text.Collator; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 53 | import java.util.ArrayList; |
| Fan Zhang | e3535d9 | 2017-08-02 17:32:43 -0700 | [diff] [blame] | 54 | import java.util.Arrays; |
| Abodunrinwa Toki | 6118469 | 2016-04-11 11:30:30 +0100 | [diff] [blame] | 55 | import java.util.List; |
| Abodunrinwa Toki | 226e452 | 2016-04-22 17:45:03 +0100 | [diff] [blame] | 56 | import java.util.Objects; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 57 | |
| Tony Mantler | 0fcd6cb | 2018-03-26 15:17:25 -0700 | [diff] [blame] | 58 | @SearchIndexable |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 59 | public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 60 | implements InputManager.InputDeviceListener, |
| Fan Zhang | 78ea7da | 2018-07-02 13:44:57 -0700 | [diff] [blame] | 61 | KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener { |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 62 | |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 63 | private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category"; |
| 64 | private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch"; |
| Clara Bayarri | ea8772a | 2016-04-01 14:36:35 +0100 | [diff] [blame] | 65 | private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper"; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 66 | |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 67 | @NonNull |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 68 | private final ArrayList<HardKeyboardDeviceInfo> mLastHardKeyboards = new ArrayList<>(); |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 69 | |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 70 | private InputManager mIm; |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 71 | @NonNull |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 72 | private PreferenceCategory mKeyboardAssistanceCategory; |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 73 | @NonNull |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 74 | private SwitchPreference mShowVirtualKeyboardSwitch; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 75 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 76 | private Intent mIntentWaitingForResult; |
| 77 | |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 78 | @Override |
| 79 | public void onCreatePreferences(Bundle bundle, String s) { |
| 80 | Activity activity = Preconditions.checkNotNull(getActivity()); |
| 81 | addPreferencesFromResource(R.xml.physical_keyboard_settings); |
| 82 | mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class)); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 83 | mKeyboardAssistanceCategory = Preconditions.checkNotNull( |
| 84 | (PreferenceCategory) findPreference(KEYBOARD_ASSISTANCE_CATEGORY)); |
| 85 | mShowVirtualKeyboardSwitch = Preconditions.checkNotNull( |
| 86 | (SwitchPreference) mKeyboardAssistanceCategory.findPreference( |
| 87 | SHOW_VIRTUAL_KEYBOARD_SWITCH)); |
| Clara Bayarri | ea8772a | 2016-04-01 14:36:35 +0100 | [diff] [blame] | 88 | findPreference(KEYBOARD_SHORTCUTS_HELPER).setOnPreferenceClickListener( |
| 89 | new Preference.OnPreferenceClickListener() { |
| 90 | @Override |
| 91 | public boolean onPreferenceClick(Preference preference) { |
| 92 | toggleKeyboardShortcutsMenu(); |
| 93 | return true; |
| 94 | } |
| 95 | }); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 96 | } |
| 97 | |
| 98 | @Override |
| 99 | public void onResume() { |
| 100 | super.onResume(); |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 101 | mLastHardKeyboards.clear(); |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 102 | scheduleUpdateHardKeyboards(); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 103 | mIm.registerInputDeviceListener(this, null); |
| 104 | mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener( |
| 105 | mShowVirtualKeyboardSwitchPreferenceChangeListener); |
| 106 | registerShowVirtualKeyboardSettingsObserver(); |
| 107 | } |
| 108 | |
| 109 | @Override |
| 110 | public void onPause() { |
| 111 | super.onPause(); |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 112 | mLastHardKeyboards.clear(); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 113 | mIm.unregisterInputDeviceListener(this); |
| 114 | mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(null); |
| 115 | unregisterShowVirtualKeyboardSettingsObserver(); |
| 116 | } |
| 117 | |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 118 | @Override |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 119 | public void onInputDeviceAdded(int deviceId) { |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 120 | scheduleUpdateHardKeyboards(); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 121 | } |
| 122 | |
| 123 | @Override |
| 124 | public void onInputDeviceRemoved(int deviceId) { |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 125 | scheduleUpdateHardKeyboards(); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | @Override |
| 129 | public void onInputDeviceChanged(int deviceId) { |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 130 | scheduleUpdateHardKeyboards(); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | @Override |
| Fan Zhang | 6507613 | 2016-08-08 10:25:13 -0700 | [diff] [blame] | 134 | public int getMetricsCategory() { |
| Fan Zhang | 31b2100 | 2019-01-16 13:49:47 -0800 | [diff] [blame] | 135 | return SettingsEnums.PHYSICAL_KEYBOARDS; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 136 | } |
| 137 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 138 | private void scheduleUpdateHardKeyboards() { |
| 139 | final Context context = getContext(); |
| 140 | ThreadUtils.postOnBackgroundThread(() -> { |
| 141 | final List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboards(context); |
| 142 | ThreadUtils.postOnMainThread(() -> updateHardKeyboards(newHardKeyboards)); |
| 143 | }); |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 144 | } |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 145 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 146 | private void updateHardKeyboards(@NonNull List<HardKeyboardDeviceInfo> newHardKeyboards) { |
| 147 | if (Objects.equals(mLastHardKeyboards, newHardKeyboards)) { |
| 148 | // Nothing has changed. Ignore. |
| 149 | return; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 150 | } |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 151 | |
| 152 | // TODO(yukawa): Maybe we should follow the style used in ConnectedDeviceDashboardFragment. |
| 153 | |
| 154 | mLastHardKeyboards.clear(); |
| 155 | mLastHardKeyboards.addAll(newHardKeyboards); |
| 156 | |
| 157 | final PreferenceScreen preferenceScreen = getPreferenceScreen(); |
| 158 | preferenceScreen.removeAll(); |
| 159 | final PreferenceCategory category = new PreferenceCategory(getPrefContext()); |
| 160 | category.setTitle(R.string.builtin_keyboard_settings_title); |
| 161 | category.setOrder(0); |
| 162 | preferenceScreen.addPreference(category); |
| 163 | |
| 164 | for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) { |
| 165 | // TODO(yukawa): Consider using com.android.settings.widget.GearPreference |
| 166 | final Preference pref = new Preference(getPrefContext()); |
| 167 | pref.setTitle(hardKeyboardDeviceInfo.mDeviceName); |
| 168 | pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel); |
| 169 | pref.setOnPreferenceClickListener(preference -> { |
| 170 | showKeyboardLayoutDialog(hardKeyboardDeviceInfo.mDeviceIdentifier); |
| 171 | return true; |
| 172 | }); |
| 173 | category.addPreference(pref); |
| 174 | } |
| 175 | |
| 176 | mKeyboardAssistanceCategory.setOrder(1); |
| 177 | preferenceScreen.addPreference(mKeyboardAssistanceCategory); |
| 178 | updateShowVirtualKeyboardSwitch(); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 179 | } |
| 180 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 181 | private void showKeyboardLayoutDialog(InputDeviceIdentifier inputDeviceIdentifier) { |
| Yohei Yukawa | 690f103 | 2018-03-19 19:20:29 -0700 | [diff] [blame] | 182 | KeyboardLayoutDialogFragment fragment = new KeyboardLayoutDialogFragment( |
| 183 | inputDeviceIdentifier); |
| 184 | fragment.setTargetFragment(this, 0); |
| tmfang | 27c84de | 2018-06-28 11:39:05 +0800 | [diff] [blame] | 185 | fragment.show(getActivity().getSupportFragmentManager(), "keyboardLayout"); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 186 | } |
| 187 | |
| 188 | private void registerShowVirtualKeyboardSettingsObserver() { |
| 189 | unregisterShowVirtualKeyboardSettingsObserver(); |
| 190 | getActivity().getContentResolver().registerContentObserver( |
| 191 | Secure.getUriFor(Secure.SHOW_IME_WITH_HARD_KEYBOARD), |
| 192 | false, |
| 193 | mContentObserver, |
| Yohei Yukawa | 966476b | 2016-06-16 00:02:01 -0700 | [diff] [blame] | 194 | UserHandle.myUserId()); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 195 | updateShowVirtualKeyboardSwitch(); |
| 196 | } |
| 197 | |
| 198 | private void unregisterShowVirtualKeyboardSettingsObserver() { |
| 199 | getActivity().getContentResolver().unregisterContentObserver(mContentObserver); |
| 200 | } |
| 201 | |
| 202 | private void updateShowVirtualKeyboardSwitch() { |
| Yohei Yukawa | 9f17254 | 2018-04-13 18:13:09 -0700 | [diff] [blame] | 203 | mShowVirtualKeyboardSwitch.setChecked( |
| 204 | Secure.getInt(getContentResolver(), Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0); |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 205 | } |
| 206 | |
| Clara Bayarri | ea8772a | 2016-04-01 14:36:35 +0100 | [diff] [blame] | 207 | private void toggleKeyboardShortcutsMenu() { |
| Clara Bayarri | fcc411c | 2016-05-16 14:16:46 +0100 | [diff] [blame] | 208 | getActivity().requestShowKeyboardShortcuts(); |
| Clara Bayarri | ea8772a | 2016-04-01 14:36:35 +0100 | [diff] [blame] | 209 | } |
| 210 | |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 211 | private final OnPreferenceChangeListener mShowVirtualKeyboardSwitchPreferenceChangeListener = |
| Yohei Yukawa | 9f17254 | 2018-04-13 18:13:09 -0700 | [diff] [blame] | 212 | (preference, newValue) -> { |
| 213 | Secure.putInt(getContentResolver(), Secure.SHOW_IME_WITH_HARD_KEYBOARD, |
| 214 | ((Boolean) newValue) ? 1 : 0); |
| 215 | return true; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 216 | }; |
| 217 | |
| 218 | private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) { |
| 219 | @Override |
| 220 | public void onChange(boolean selfChange) { |
| 221 | updateShowVirtualKeyboardSwitch(); |
| 222 | } |
| 223 | }; |
| Abodunrinwa Toki | 5f0b59b | 2016-01-25 23:02:23 +0000 | [diff] [blame] | 224 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 225 | @Override |
| 226 | public void onSetupKeyboardLayouts(InputDeviceIdentifier inputDeviceIdentifier) { |
| 227 | final Intent intent = new Intent(Intent.ACTION_MAIN); |
| 228 | intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class); |
| 229 | intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER, |
| 230 | inputDeviceIdentifier); |
| 231 | mIntentWaitingForResult = intent; |
| 232 | startActivityForResult(intent, 0); |
| 233 | } |
| Fan Zhang | e3535d9 | 2017-08-02 17:32:43 -0700 | [diff] [blame] | 234 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 235 | @Override |
| 236 | public void onActivityResult(int requestCode, int resultCode, Intent data) { |
| 237 | super.onActivityResult(requestCode, resultCode, data); |
| Abodunrinwa Toki | 5f0b59b | 2016-01-25 23:02:23 +0000 | [diff] [blame] | 238 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 239 | if (mIntentWaitingForResult != null) { |
| 240 | InputDeviceIdentifier inputDeviceIdentifier = mIntentWaitingForResult |
| 241 | .getParcelableExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER); |
| 242 | mIntentWaitingForResult = null; |
| 243 | showKeyboardLayoutDialog(inputDeviceIdentifier); |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 244 | } |
| 245 | } |
| 246 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 247 | private static String getLayoutLabel(@NonNull InputDevice device, |
| 248 | @NonNull Context context, @NonNull InputManager im) { |
| 249 | final String currentLayoutDesc = |
| 250 | im.getCurrentKeyboardLayoutForInputDevice(device.getIdentifier()); |
| 251 | if (currentLayoutDesc == null) { |
| 252 | return context.getString(R.string.keyboard_layout_default_label); |
| Abodunrinwa Toki | 5f0b59b | 2016-01-25 23:02:23 +0000 | [diff] [blame] | 253 | } |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 254 | final KeyboardLayout currentLayout = im.getKeyboardLayout(currentLayoutDesc); |
| 255 | if (currentLayout == null) { |
| 256 | return context.getString(R.string.keyboard_layout_default_label); |
| 257 | } |
| 258 | // If current layout is specified but the layout is null, just return an empty string |
| 259 | // instead of falling back to R.string.keyboard_layout_default_label. |
| 260 | return TextUtils.emptyIfNull(currentLayout.getLabel()); |
| 261 | } |
| Abodunrinwa Toki | 5f0b59b | 2016-01-25 23:02:23 +0000 | [diff] [blame] | 262 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 263 | @NonNull |
| 264 | static List<HardKeyboardDeviceInfo> getHardKeyboards(@NonNull Context context) { |
| 265 | final List<HardKeyboardDeviceInfo> keyboards = new ArrayList<>(); |
| 266 | final InputManager im = context.getSystemService(InputManager.class); |
| 267 | if (im == null) { |
| 268 | return new ArrayList<>(); |
| 269 | } |
| 270 | for (int deviceId : InputDevice.getDeviceIds()) { |
| 271 | final InputDevice device = InputDevice.getDevice(deviceId); |
| 272 | if (device == null || device.isVirtual() || !device.isFullKeyboard()) { |
| 273 | continue; |
| Abodunrinwa Toki | 5f0b59b | 2016-01-25 23:02:23 +0000 | [diff] [blame] | 274 | } |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 275 | keyboards.add(new HardKeyboardDeviceInfo( |
| 276 | device.getName(), device.getIdentifier(), getLayoutLabel(device, context, im))); |
| Abodunrinwa Toki | 6118469 | 2016-04-11 11:30:30 +0100 | [diff] [blame] | 277 | } |
| 278 | |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 279 | // We intentionally don't reuse Comparator because Collator may not be thread-safe. |
| 280 | final Collator collator = Collator.getInstance(); |
| 281 | keyboards.sort((a, b) -> { |
| 282 | int result = collator.compare(a.mDeviceName, b.mDeviceName); |
| 283 | if (result != 0) { |
| 284 | return result; |
| Abodunrinwa Toki | 6118469 | 2016-04-11 11:30:30 +0100 | [diff] [blame] | 285 | } |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 286 | result = a.mDeviceIdentifier.getDescriptor().compareTo( |
| 287 | b.mDeviceIdentifier.getDescriptor()); |
| 288 | if (result != 0) { |
| 289 | return result; |
| 290 | } |
| 291 | return collator.compare(a.mLayoutLabel, b.mLayoutLabel); |
| 292 | }); |
| 293 | return keyboards; |
| Abodunrinwa Toki | 5f0b59b | 2016-01-25 23:02:23 +0000 | [diff] [blame] | 294 | } |
| 295 | |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 296 | public static final class HardKeyboardDeviceInfo { |
| 297 | @NonNull |
| 298 | public final String mDeviceName; |
| 299 | @NonNull |
| 300 | public final InputDeviceIdentifier mDeviceIdentifier; |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 301 | @NonNull |
| 302 | public final String mLayoutLabel; |
| Abodunrinwa Toki | 5f0b59b | 2016-01-25 23:02:23 +0000 | [diff] [blame] | 303 | |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 304 | public HardKeyboardDeviceInfo( |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 305 | @Nullable String deviceName, |
| 306 | @NonNull InputDeviceIdentifier deviceIdentifier, |
| 307 | @NonNull String layoutLabel) { |
| 308 | mDeviceName = TextUtils.emptyIfNull(deviceName); |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 309 | mDeviceIdentifier = deviceIdentifier; |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 310 | mLayoutLabel = layoutLabel; |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 311 | } |
| 312 | |
| 313 | @Override |
| 314 | public boolean equals(Object o) { |
| 315 | if (o == this) return true; |
| 316 | if (o == null) return false; |
| 317 | |
| 318 | if (!(o instanceof HardKeyboardDeviceInfo)) return false; |
| 319 | |
| 320 | final HardKeyboardDeviceInfo that = (HardKeyboardDeviceInfo) o; |
| 321 | if (!TextUtils.equals(mDeviceName, that.mDeviceName)) { |
| 322 | return false; |
| 323 | } |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 324 | if (!Objects.equals(mDeviceIdentifier, that.mDeviceIdentifier)) { |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 325 | return false; |
| 326 | } |
| Yohei Yukawa | 7129b37 | 2018-03-08 13:47:56 -0800 | [diff] [blame] | 327 | if (!TextUtils.equals(mLayoutLabel, that.mLayoutLabel)) { |
| Yohei Yukawa | 1dff385 | 2016-04-01 03:53:34 -0700 | [diff] [blame] | 328 | return false; |
| 329 | } |
| 330 | |
| 331 | return true; |
| 332 | } |
| 333 | } |
| 334 | |
| Raff Tsai | ac3e0d0 | 2019-09-19 17:06:45 +0800 | [diff] [blame^] | 335 | public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = |
| Tadashi G. Takaoka | 7bbc632 | 2017-01-10 15:02:22 +0900 | [diff] [blame] | 336 | new BaseSearchIndexProvider() { |
| Fan Zhang | e3535d9 | 2017-08-02 17:32:43 -0700 | [diff] [blame] | 337 | @Override |
| 338 | public List<SearchIndexableResource> getXmlResourcesToIndex( |
| 339 | Context context, boolean enabled) { |
| 340 | final SearchIndexableResource sir = new SearchIndexableResource(context); |
| 341 | sir.xmlResId = R.xml.physical_keyboard_settings; |
| 342 | return Arrays.asList(sir); |
| 343 | } |
| 344 | }; |
| Abodunrinwa Toki | 976bb3f | 2016-01-20 18:43:20 +0000 | [diff] [blame] | 345 | } |