Home | History | Annotate | Download | only in inputmethod
      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 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.app.Activity;
     22 import android.app.LoaderManager;
     23 import android.content.AsyncTaskLoader;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.Loader;
     27 import android.database.ContentObserver;
     28 import android.hardware.input.InputDeviceIdentifier;
     29 import android.hardware.input.InputManager;
     30 import android.hardware.input.KeyboardLayout;
     31 import android.os.Bundle;
     32 import android.os.Handler;
     33 import android.os.UserHandle;
     34 import android.provider.Settings.Secure;
     35 import android.support.v14.preference.SwitchPreference;
     36 import android.support.v7.preference.Preference;
     37 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
     38 import android.support.v7.preference.PreferenceCategory;
     39 import android.support.v7.preference.PreferenceScreen;
     40 import android.text.TextUtils;
     41 import android.view.InputDevice;
     42 import android.view.inputmethod.InputMethodInfo;
     43 import android.view.inputmethod.InputMethodManager;
     44 import android.view.inputmethod.InputMethodSubtype;
     45 
     46 import com.android.internal.inputmethod.InputMethodUtils;
     47 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     48 import com.android.internal.util.Preconditions;
     49 import com.android.settings.R;
     50 import com.android.settings.Settings;
     51 import com.android.settings.SettingsPreferenceFragment;
     52 import com.android.settings.search.BaseSearchIndexProvider;
     53 import com.android.settings.search.Indexable;
     54 import com.android.settings.search.SearchIndexableRaw;
     55 import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil;
     56 
     57 import java.text.Collator;
     58 import java.util.ArrayList;
     59 import java.util.Collections;
     60 import java.util.HashMap;
     61 import java.util.HashSet;
     62 import java.util.List;
     63 import java.util.Objects;
     64 
     65 public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
     66         implements InputManager.InputDeviceListener, Indexable {
     67 
     68     private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category";
     69     private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch";
     70     private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper";
     71     private static final String IM_SUBTYPE_MODE_KEYBOARD = "keyboard";
     72 
     73     @NonNull
     74     private final List<HardKeyboardDeviceInfo> mLastHardKeyboards = new ArrayList<>();
     75     @NonNull
     76     private final List<KeyboardInfoPreference> mTempKeyboardInfoList = new ArrayList<>();
     77 
     78     @NonNull
     79     private final HashSet<Integer> mLoaderIDs = new HashSet<>();
     80     private int mNextLoaderId = 0;
     81 
     82     private InputManager mIm;
     83     @NonNull
     84     private PreferenceCategory mKeyboardAssistanceCategory;
     85     @NonNull
     86     private SwitchPreference mShowVirtualKeyboardSwitch;
     87     @NonNull
     88     private InputMethodUtils.InputMethodSettings mSettings;
     89 
     90     @Override
     91     public void onCreatePreferences(Bundle bundle, String s) {
     92         Activity activity = Preconditions.checkNotNull(getActivity());
     93         addPreferencesFromResource(R.xml.physical_keyboard_settings);
     94         mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class));
     95         mSettings = new InputMethodUtils.InputMethodSettings(
     96                 activity.getResources(),
     97                 getContentResolver(),
     98                 new HashMap<>(),
     99                 new ArrayList<>(),
    100                 UserHandle.myUserId(),
    101                 false /* copyOnWrite */);
    102         mKeyboardAssistanceCategory = Preconditions.checkNotNull(
    103                 (PreferenceCategory) findPreference(KEYBOARD_ASSISTANCE_CATEGORY));
    104         mShowVirtualKeyboardSwitch = Preconditions.checkNotNull(
    105                 (SwitchPreference) mKeyboardAssistanceCategory.findPreference(
    106                         SHOW_VIRTUAL_KEYBOARD_SWITCH));
    107         findPreference(KEYBOARD_SHORTCUTS_HELPER).setOnPreferenceClickListener(
    108                 new Preference.OnPreferenceClickListener() {
    109                     @Override
    110                     public boolean onPreferenceClick(Preference preference) {
    111                         toggleKeyboardShortcutsMenu();
    112                         return true;
    113                     }
    114                 });
    115     }
    116 
    117     @Override
    118     public void onResume() {
    119         super.onResume();
    120         clearLoader();
    121         mLastHardKeyboards.clear();
    122         updateHardKeyboards();
    123         mIm.registerInputDeviceListener(this, null);
    124         mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(
    125                 mShowVirtualKeyboardSwitchPreferenceChangeListener);
    126         registerShowVirtualKeyboardSettingsObserver();
    127     }
    128 
    129     @Override
    130     public void onPause() {
    131         super.onPause();
    132         clearLoader();
    133         mLastHardKeyboards.clear();
    134         mIm.unregisterInputDeviceListener(this);
    135         mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(null);
    136         unregisterShowVirtualKeyboardSettingsObserver();
    137     }
    138 
    139     private void onLoadFinishedInternal(
    140             final int loaderId, @NonNull final List<Keyboards> keyboardsList) {
    141         if (!mLoaderIDs.remove(loaderId)) {
    142             // Already destroyed loader.  Ignore.
    143             return;
    144         }
    145 
    146         Collections.sort(keyboardsList);
    147         final PreferenceScreen preferenceScreen = getPreferenceScreen();
    148         preferenceScreen.removeAll();
    149         for (Keyboards keyboards : keyboardsList) {
    150             final PreferenceCategory category = new PreferenceCategory(getPrefContext(), null);
    151             category.setTitle(keyboards.mDeviceInfo.mDeviceName);
    152             category.setOrder(0);
    153             preferenceScreen.addPreference(category);
    154             for (Keyboards.KeyboardInfo info : keyboards.mKeyboardInfoList) {
    155                 mTempKeyboardInfoList.clear();
    156                 final InputMethodInfo imi = info.mImi;
    157                 final InputMethodSubtype imSubtype = info.mImSubtype;
    158                 if (imi != null) {
    159                     KeyboardInfoPreference pref =
    160                             new KeyboardInfoPreference(getPrefContext(), info);
    161                     pref.setOnPreferenceClickListener(preference -> {
    162                         showKeyboardLayoutScreen(
    163                                 keyboards.mDeviceInfo.mDeviceIdentifier, imi, imSubtype);
    164                         return true;
    165                     });
    166                     mTempKeyboardInfoList.add(pref);
    167                     Collections.sort(mTempKeyboardInfoList);
    168                 }
    169                 for (KeyboardInfoPreference pref : mTempKeyboardInfoList) {
    170                     category.addPreference(pref);
    171                 }
    172             }
    173         }
    174         mTempKeyboardInfoList.clear();
    175         mKeyboardAssistanceCategory.setOrder(1);
    176         preferenceScreen.addPreference(mKeyboardAssistanceCategory);
    177         updateShowVirtualKeyboardSwitch();
    178     }
    179 
    180     @Override
    181     public void onInputDeviceAdded(int deviceId) {
    182         updateHardKeyboards();
    183     }
    184 
    185     @Override
    186     public void onInputDeviceRemoved(int deviceId) {
    187         updateHardKeyboards();
    188     }
    189 
    190     @Override
    191     public void onInputDeviceChanged(int deviceId) {
    192         updateHardKeyboards();
    193     }
    194 
    195     @Override
    196     public int getMetricsCategory() {
    197         return MetricsEvent.PHYSICAL_KEYBOARDS;
    198     }
    199 
    200     @NonNull
    201     public static List<HardKeyboardDeviceInfo> getHardKeyboards() {
    202         final List<HardKeyboardDeviceInfo> keyboards = new ArrayList<>();
    203         final int[] devicesIds = InputDevice.getDeviceIds();
    204         for (int deviceId : devicesIds) {
    205             final InputDevice device = InputDevice.getDevice(deviceId);
    206             if (device != null && !device.isVirtual() && device.isFullKeyboard()) {
    207                 keyboards.add(new HardKeyboardDeviceInfo(device.getName(), device.getIdentifier()));
    208             }
    209         }
    210         return keyboards;
    211     }
    212 
    213     private void updateHardKeyboards() {
    214         final List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboards();
    215         if (!Objects.equals(newHardKeyboards, mLastHardKeyboards)) {
    216             clearLoader();
    217             mLastHardKeyboards.clear();
    218             mLastHardKeyboards.addAll(newHardKeyboards);
    219             mLoaderIDs.add(mNextLoaderId);
    220             getLoaderManager().initLoader(mNextLoaderId, null,
    221                     new Callbacks(getContext(), this, mLastHardKeyboards));
    222             ++mNextLoaderId;
    223         }
    224     }
    225 
    226     private void showKeyboardLayoutScreen(
    227             @NonNull InputDeviceIdentifier inputDeviceIdentifier,
    228             @NonNull InputMethodInfo imi,
    229             @Nullable InputMethodSubtype imSubtype) {
    230         final Intent intent = new Intent(Intent.ACTION_MAIN);
    231         intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class);
    232         intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
    233                 inputDeviceIdentifier);
    234         intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_METHOD_INFO, imi);
    235         intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_METHOD_SUBTYPE, imSubtype);
    236         startActivity(intent);
    237     }
    238 
    239     private void clearLoader() {
    240         for (final int loaderId : mLoaderIDs) {
    241             getLoaderManager().destroyLoader(loaderId);
    242         }
    243         mLoaderIDs.clear();
    244     }
    245 
    246     private void registerShowVirtualKeyboardSettingsObserver() {
    247         unregisterShowVirtualKeyboardSettingsObserver();
    248         getActivity().getContentResolver().registerContentObserver(
    249                 Secure.getUriFor(Secure.SHOW_IME_WITH_HARD_KEYBOARD),
    250                 false,
    251                 mContentObserver,
    252                 UserHandle.myUserId());
    253         updateShowVirtualKeyboardSwitch();
    254     }
    255 
    256     private void unregisterShowVirtualKeyboardSettingsObserver() {
    257         getActivity().getContentResolver().unregisterContentObserver(mContentObserver);
    258     }
    259 
    260     private void updateShowVirtualKeyboardSwitch() {
    261         mShowVirtualKeyboardSwitch.setChecked(mSettings.isShowImeWithHardKeyboardEnabled());
    262     }
    263 
    264     private void toggleKeyboardShortcutsMenu() {
    265         getActivity().requestShowKeyboardShortcuts();
    266     }
    267 
    268     private final OnPreferenceChangeListener mShowVirtualKeyboardSwitchPreferenceChangeListener =
    269             new OnPreferenceChangeListener() {
    270                 @Override
    271                 public boolean onPreferenceChange(Preference preference, Object newValue) {
    272                     mSettings.setShowImeWithHardKeyboard((Boolean) newValue);
    273                     return true;
    274                 }
    275             };
    276 
    277     private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) {
    278         @Override
    279         public void onChange(boolean selfChange) {
    280             updateShowVirtualKeyboardSwitch();
    281         }
    282     };
    283 
    284     private static final class Callbacks implements LoaderManager.LoaderCallbacks<List<Keyboards>> {
    285         @NonNull
    286         final Context mContext;
    287         @NonNull
    288         final PhysicalKeyboardFragment mPhysicalKeyboardFragment;
    289         @NonNull
    290         final List<HardKeyboardDeviceInfo> mHardKeyboards;
    291         public Callbacks(
    292                 @NonNull Context context,
    293                 @NonNull PhysicalKeyboardFragment physicalKeyboardFragment,
    294                 @NonNull List<HardKeyboardDeviceInfo> hardKeyboards) {
    295             mContext = context;
    296             mPhysicalKeyboardFragment = physicalKeyboardFragment;
    297             mHardKeyboards = hardKeyboards;
    298         }
    299 
    300         @Override
    301         public Loader<List<Keyboards>> onCreateLoader(int id, Bundle args) {
    302             return new KeyboardLayoutLoader(mContext, mHardKeyboards);
    303         }
    304 
    305         @Override
    306         public void onLoadFinished(Loader<List<Keyboards>> loader, List<Keyboards> data) {
    307             mPhysicalKeyboardFragment.onLoadFinishedInternal(loader.getId(), data);
    308         }
    309 
    310         @Override
    311         public void onLoaderReset(Loader<List<Keyboards>> loader) {
    312         }
    313     }
    314 
    315     private static final class KeyboardLayoutLoader extends AsyncTaskLoader<List<Keyboards>> {
    316         @NonNull
    317         private final List<HardKeyboardDeviceInfo> mHardKeyboards;
    318 
    319         public KeyboardLayoutLoader(
    320                 @NonNull Context context,
    321                 @NonNull List<HardKeyboardDeviceInfo> hardKeyboards) {
    322             super(context);
    323             mHardKeyboards = Preconditions.checkNotNull(hardKeyboards);
    324         }
    325 
    326         private Keyboards loadInBackground(HardKeyboardDeviceInfo deviceInfo) {
    327             final ArrayList<Keyboards.KeyboardInfo> keyboardInfoList = new ArrayList<>();
    328             final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
    329             final InputManager im = getContext().getSystemService(InputManager.class);
    330             if (imm != null && im != null) {
    331                 for (InputMethodInfo imi : imm.getEnabledInputMethodList()) {
    332                     final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(
    333                             imi, true /* allowsImplicitlySelectedSubtypes */);
    334                     if (subtypes.isEmpty()) {
    335                         // Here we use null to indicate that this IME has no subtype.
    336                         final InputMethodSubtype nullSubtype = null;
    337                         final KeyboardLayout layout = im.getKeyboardLayoutForInputDevice(
    338                                 deviceInfo.mDeviceIdentifier, imi, nullSubtype);
    339                         keyboardInfoList.add(new Keyboards.KeyboardInfo(imi, nullSubtype, layout));
    340                         continue;
    341                     }
    342 
    343                     // If the IME supports subtypes, we pick up "keyboard" subtypes only.
    344                     final int N = subtypes.size();
    345                     for (int i = 0; i < N; ++i) {
    346                         final InputMethodSubtype subtype = subtypes.get(i);
    347                         if (!IM_SUBTYPE_MODE_KEYBOARD.equalsIgnoreCase(subtype.getMode())) {
    348                             continue;
    349                         }
    350                         final KeyboardLayout layout = im.getKeyboardLayoutForInputDevice(
    351                                 deviceInfo.mDeviceIdentifier, imi, subtype);
    352                         keyboardInfoList.add(new Keyboards.KeyboardInfo(imi, subtype, layout));
    353                     }
    354                 }
    355             }
    356             return new Keyboards(deviceInfo, keyboardInfoList);
    357         }
    358 
    359         @Override
    360         public List<Keyboards> loadInBackground() {
    361             List<Keyboards> keyboardsList = new ArrayList<>(mHardKeyboards.size());
    362             for (HardKeyboardDeviceInfo deviceInfo : mHardKeyboards) {
    363                 keyboardsList.add(loadInBackground(deviceInfo));
    364             }
    365             return keyboardsList;
    366         }
    367 
    368         @Override
    369         protected void onStartLoading() {
    370             super.onStartLoading();
    371             forceLoad();
    372         }
    373 
    374         @Override
    375         protected void onStopLoading() {
    376             super.onStopLoading();
    377             cancelLoad();
    378         }
    379     }
    380 
    381     public static final class HardKeyboardDeviceInfo {
    382         @NonNull
    383         public final String mDeviceName;
    384         @NonNull
    385         public final InputDeviceIdentifier mDeviceIdentifier;
    386 
    387         public HardKeyboardDeviceInfo(
    388                 @Nullable final String deviceName,
    389                 @NonNull final InputDeviceIdentifier deviceIdentifier) {
    390             mDeviceName = deviceName != null ? deviceName : "";
    391             mDeviceIdentifier = deviceIdentifier;
    392         }
    393 
    394         @Override
    395         public boolean equals(Object o) {
    396             if (o == this) return true;
    397             if (o == null) return false;
    398 
    399             if (!(o instanceof HardKeyboardDeviceInfo)) return false;
    400 
    401             final HardKeyboardDeviceInfo that = (HardKeyboardDeviceInfo) o;
    402             if (!TextUtils.equals(mDeviceName, that.mDeviceName)) {
    403                 return false;
    404             }
    405             if (mDeviceIdentifier.getVendorId() != that.mDeviceIdentifier.getVendorId()) {
    406                 return false;
    407             }
    408             if (mDeviceIdentifier.getProductId() != that.mDeviceIdentifier.getProductId()) {
    409                 return false;
    410             }
    411             if (!TextUtils.equals(mDeviceIdentifier.getDescriptor(),
    412                     that.mDeviceIdentifier.getDescriptor())) {
    413                 return false;
    414             }
    415 
    416             return true;
    417         }
    418     }
    419 
    420     public static final class Keyboards implements Comparable<Keyboards> {
    421         @NonNull
    422         public final HardKeyboardDeviceInfo mDeviceInfo;
    423         @NonNull
    424         public final ArrayList<KeyboardInfo> mKeyboardInfoList;
    425         @NonNull
    426         public final Collator mCollator = Collator.getInstance();
    427 
    428         public Keyboards(
    429                 @NonNull final HardKeyboardDeviceInfo deviceInfo,
    430                 @NonNull final ArrayList<KeyboardInfo> keyboardInfoList) {
    431             mDeviceInfo = deviceInfo;
    432             mKeyboardInfoList = keyboardInfoList;
    433         }
    434 
    435         @Override
    436         public int compareTo(@NonNull Keyboards another) {
    437             return mCollator.compare(mDeviceInfo.mDeviceName, another.mDeviceInfo.mDeviceName);
    438         }
    439 
    440         public static final class KeyboardInfo {
    441             @NonNull
    442             public final InputMethodInfo mImi;
    443             @Nullable
    444             public final InputMethodSubtype mImSubtype;
    445             @NonNull
    446             public final KeyboardLayout mLayout;
    447 
    448             public KeyboardInfo(
    449                     @NonNull final InputMethodInfo imi,
    450                     @Nullable final InputMethodSubtype imSubtype,
    451                     @NonNull final KeyboardLayout layout) {
    452                 mImi = imi;
    453                 mImSubtype = imSubtype;
    454                 mLayout = layout;
    455             }
    456         }
    457     }
    458 
    459     static final class KeyboardInfoPreference extends Preference {
    460 
    461         @NonNull
    462         private final CharSequence mImeName;
    463         @Nullable
    464         private final CharSequence mImSubtypeName;
    465         @NonNull
    466         private final Collator collator = Collator.getInstance();
    467 
    468         private KeyboardInfoPreference(
    469                 @NonNull Context context, @NonNull Keyboards.KeyboardInfo info) {
    470             super(context);
    471             mImeName = info.mImi.loadLabel(context.getPackageManager());
    472             mImSubtypeName = getImSubtypeName(context, info.mImi, info.mImSubtype);
    473             setTitle(formatDisplayName(context, mImeName, mImSubtypeName));
    474             if (info.mLayout != null) {
    475                 setSummary(info.mLayout.getLabel());
    476             }
    477         }
    478 
    479         @NonNull
    480         static CharSequence getDisplayName(
    481                 @NonNull Context context, @NonNull InputMethodInfo imi,
    482                 @Nullable InputMethodSubtype imSubtype) {
    483             final CharSequence imeName = imi.loadLabel(context.getPackageManager());
    484             final CharSequence imSubtypeName = getImSubtypeName(context, imi, imSubtype);
    485             return formatDisplayName(context, imeName, imSubtypeName);
    486         }
    487 
    488         private static CharSequence formatDisplayName(
    489                 @NonNull Context context,
    490                 @NonNull CharSequence imeName, @Nullable CharSequence imSubtypeName) {
    491             if (imSubtypeName == null) {
    492                 return imeName;
    493             }
    494             return String.format(
    495                     context.getString(R.string.physical_device_title), imeName, imSubtypeName);
    496         }
    497 
    498         @Nullable
    499         private static CharSequence getImSubtypeName(
    500                 @NonNull Context context, @NonNull InputMethodInfo imi,
    501                 @Nullable InputMethodSubtype imSubtype) {
    502             if (imSubtype != null) {
    503                 return InputMethodAndSubtypeUtil.getSubtypeLocaleNameAsSentence(
    504                         imSubtype, context, imi);
    505             }
    506             return null;
    507         }
    508 
    509         @Override
    510         public int compareTo(@NonNull Preference object) {
    511             if (!(object instanceof KeyboardInfoPreference)) {
    512                 return super.compareTo(object);
    513             }
    514             KeyboardInfoPreference another = (KeyboardInfoPreference) object;
    515             int result = compare(mImeName, another.mImeName);
    516             if (result == 0) {
    517                 result = compare(mImSubtypeName, another.mImSubtypeName);
    518             }
    519             return result;
    520         }
    521 
    522         private int compare(@Nullable CharSequence lhs, @Nullable CharSequence rhs) {
    523             if (!TextUtils.isEmpty(lhs) && !TextUtils.isEmpty(rhs)) {
    524                 return collator.compare(lhs.toString(), rhs.toString());
    525             } else if (TextUtils.isEmpty(lhs) && TextUtils.isEmpty(rhs)) {
    526                 return 0;
    527             } else if (!TextUtils.isEmpty(lhs)) {
    528                 return -1;
    529             } else {
    530                 return 1;
    531             }
    532         }
    533     }
    534 
    535     public static List<InputDevice> getPhysicalFullKeyboards() {
    536         List<InputDevice> keyboards = null;
    537         for (final int deviceId : InputDevice.getDeviceIds()) {
    538             final InputDevice device = InputDevice.getDevice(deviceId);
    539             if (device != null && !device.isVirtual() && device.isFullKeyboard()) {
    540                 if (keyboards == null) keyboards = new ArrayList<>();
    541                 keyboards.add(device);
    542             }
    543         }
    544         return (keyboards == null) ? Collections.emptyList() : keyboards;
    545     }
    546 
    547     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
    548             new BaseSearchIndexProvider() {
    549         @Override
    550         public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
    551             final InputManager inputManager = (InputManager) context.getSystemService(
    552                     Context.INPUT_SERVICE);
    553             final String screenTitle = context.getString(R.string.physical_keyboard_title);
    554             final List<SearchIndexableRaw> indexes = new ArrayList<>();
    555             for (final InputDevice device : getPhysicalFullKeyboards()) {
    556                 final String keyboardLayoutDescriptor = inputManager
    557                         .getCurrentKeyboardLayoutForInputDevice(device.getIdentifier());
    558                 final KeyboardLayout keyboardLayout = (keyboardLayoutDescriptor != null)
    559                         ? inputManager.getKeyboardLayout(keyboardLayoutDescriptor) : null;
    560                 final String summary = (keyboardLayout != null)
    561                         ? keyboardLayout.toString()
    562                         : context.getString(R.string.keyboard_layout_default_label);
    563                 final SearchIndexableRaw index = new SearchIndexableRaw(context);
    564                 index.key = device.getName();
    565                 index.title = device.getName();
    566                 index.summaryOn = summary;
    567                 index.summaryOff = summary;
    568                 index.screenTitle = screenTitle;
    569                 indexes.add(index);
    570             }
    571             return indexes;
    572         }
    573     };
    574 }
    575