Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2011 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.bluetooth;
     18 
     19 import android.app.Activity;
     20 import android.bluetooth.BluetoothAdapter;
     21 import android.bluetooth.BluetoothDevice;
     22 import android.content.BroadcastReceiver;
     23 import android.content.ContentResolver;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.IntentFilter;
     27 import android.content.res.Resources;
     28 import android.os.Bundle;
     29 import android.provider.Settings;
     30 import android.support.v7.preference.Preference;
     31 import android.support.v7.preference.PreferenceCategory;
     32 import android.support.v7.preference.PreferenceGroup;
     33 import android.support.v7.preference.PreferenceScreen;
     34 import android.text.BidiFormatter;
     35 import android.text.Spannable;
     36 import android.text.style.TextAppearanceSpan;
     37 import android.util.Log;
     38 import android.view.Menu;
     39 import android.view.MenuInflater;
     40 import android.view.MenuItem;
     41 import android.view.View;
     42 import android.widget.TextView;
     43 import com.android.internal.logging.MetricsLogger;
     44 import com.android.internal.logging.MetricsProto.MetricsEvent;
     45 import com.android.settings.LinkifyUtils;
     46 import com.android.settings.R;
     47 import com.android.settings.SettingsActivity;
     48 import com.android.settings.dashboard.SummaryLoader;
     49 import com.android.settings.location.ScanningSettings;
     50 import com.android.settings.search.BaseSearchIndexProvider;
     51 import com.android.settings.search.Indexable;
     52 import com.android.settings.search.SearchIndexableRaw;
     53 import com.android.settings.widget.SwitchBar;
     54 import com.android.settingslib.bluetooth.BluetoothCallback;
     55 import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
     56 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
     57 import com.android.settingslib.bluetooth.LocalBluetoothManager;
     58 
     59 import java.util.ArrayList;
     60 import java.util.List;
     61 import java.util.Locale;
     62 import java.util.Set;
     63 
     64 import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
     65 
     66 /**
     67  * BluetoothSettings is the Settings screen for Bluetooth configuration and
     68  * connection management.
     69  */
     70 public final class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable {
     71     private static final String TAG = "BluetoothSettings";
     72 
     73     private static final int MENU_ID_SCAN = Menu.FIRST;
     74     private static final int MENU_ID_RENAME_DEVICE = Menu.FIRST + 1;
     75     private static final int MENU_ID_SHOW_RECEIVED = Menu.FIRST + 2;
     76 
     77     /* Private intent to show the list of received files */
     78     private static final String BTOPP_ACTION_OPEN_RECEIVED_FILES =
     79             "android.btopp.intent.action.OPEN_RECEIVED_FILES";
     80 
     81     private static final String KEY_PAIRED_DEVICES = "paired_devices";
     82 
     83     private static View mSettingsDialogView = null;
     84 
     85     private BluetoothEnabler mBluetoothEnabler;
     86 
     87     private PreferenceGroup mPairedDevicesCategory;
     88     private PreferenceGroup mAvailableDevicesCategory;
     89     private boolean mAvailableDevicesCategoryIsPresent;
     90 
     91     private boolean mInitialScanStarted;
     92     private boolean mInitiateDiscoverable;
     93 
     94     private SwitchBar mSwitchBar;
     95 
     96     private final IntentFilter mIntentFilter;
     97 
     98 
     99     // accessed from inner class (not private to avoid thunks)
    100     Preference mMyDevicePreference;
    101 
    102     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    103         @Override
    104         public void onReceive(Context context, Intent intent) {
    105             final String action = intent.getAction();
    106             final int state =
    107                 intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
    108 
    109             if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) {
    110                 updateDeviceName(context);
    111             }
    112 
    113             if (state == BluetoothAdapter.STATE_ON) {
    114                 mInitiateDiscoverable = true;
    115             }
    116         }
    117 
    118         private void updateDeviceName(Context context) {
    119             if (mLocalAdapter.isEnabled() && mMyDevicePreference != null) {
    120                 final Resources res = context.getResources();
    121                 final Locale locale = res.getConfiguration().getLocales().get(0);
    122                 final BidiFormatter bidiFormatter = BidiFormatter.getInstance(locale);
    123                 mMyDevicePreference.setSummary(res.getString(
    124                             R.string.bluetooth_is_visible_message,
    125                             bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
    126             }
    127         }
    128     };
    129 
    130     public BluetoothSettings() {
    131         super(DISALLOW_CONFIG_BLUETOOTH);
    132         mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
    133     }
    134 
    135     @Override
    136     protected int getMetricsCategory() {
    137         return MetricsEvent.BLUETOOTH;
    138     }
    139 
    140     @Override
    141     public void onActivityCreated(Bundle savedInstanceState) {
    142         super.onActivityCreated(savedInstanceState);
    143         mInitialScanStarted = false;
    144         mInitiateDiscoverable = true;
    145 
    146         final SettingsActivity activity = (SettingsActivity) getActivity();
    147         mSwitchBar = activity.getSwitchBar();
    148 
    149         mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);
    150         mBluetoothEnabler.setupSwitchBar();
    151     }
    152 
    153     @Override
    154     public void onDestroyView() {
    155         super.onDestroyView();
    156 
    157         mBluetoothEnabler.teardownSwitchBar();
    158     }
    159 
    160     @Override
    161     void addPreferencesForActivity() {
    162         addPreferencesFromResource(R.xml.bluetooth_settings);
    163 
    164         mPairedDevicesCategory = new PreferenceCategory(getPrefContext());
    165         mPairedDevicesCategory.setKey(KEY_PAIRED_DEVICES);
    166         mPairedDevicesCategory.setOrder(1);
    167         getPreferenceScreen().addPreference(mPairedDevicesCategory);
    168 
    169         mAvailableDevicesCategory = new BluetoothProgressCategory(getActivity());
    170         mAvailableDevicesCategory.setSelectable(false);
    171         mAvailableDevicesCategory.setOrder(2);
    172         getPreferenceScreen().addPreference(mAvailableDevicesCategory);
    173 
    174         mMyDevicePreference = new Preference(getPrefContext());
    175         mMyDevicePreference.setSelectable(false);
    176         mMyDevicePreference.setOrder(3);
    177         getPreferenceScreen().addPreference(mMyDevicePreference);
    178 
    179         setHasOptionsMenu(true);
    180     }
    181 
    182     @Override
    183     public void onResume() {
    184         // resume BluetoothEnabler before calling super.onResume() so we don't get
    185         // any onDeviceAdded() callbacks before setting up view in updateContent()
    186         if (mBluetoothEnabler != null) {
    187             mBluetoothEnabler.resume(getActivity());
    188         }
    189         super.onResume();
    190 
    191         mInitiateDiscoverable = true;
    192 
    193         if (isUiRestricted()) {
    194             setDeviceListGroup(getPreferenceScreen());
    195             if (!isUiRestrictedByOnlyAdmin()) {
    196                 getEmptyTextView().setText(R.string.bluetooth_empty_list_user_restricted);
    197             }
    198             removeAllDevices();
    199             return;
    200         }
    201 
    202         getActivity().registerReceiver(mReceiver, mIntentFilter);
    203         if (mLocalAdapter != null) {
    204             updateContent(mLocalAdapter.getBluetoothState());
    205         }
    206     }
    207 
    208     @Override
    209     public void onPause() {
    210         super.onPause();
    211         if (mBluetoothEnabler != null) {
    212             mBluetoothEnabler.pause();
    213         }
    214 
    215         // Make the device only visible to connected devices.
    216         mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
    217 
    218         if (isUiRestricted()) {
    219             return;
    220         }
    221 
    222         getActivity().unregisterReceiver(mReceiver);
    223     }
    224 
    225     @Override
    226     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    227         if (mLocalAdapter == null) return;
    228         // If the user is not allowed to configure bluetooth, do not show the menu.
    229         if (isUiRestricted()) return;
    230 
    231         boolean bluetoothIsEnabled = mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON;
    232         boolean isDiscovering = mLocalAdapter.isDiscovering();
    233         int textId = isDiscovering ? R.string.bluetooth_searching_for_devices :
    234             R.string.bluetooth_search_for_devices;
    235         menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)
    236                 .setEnabled(bluetoothIsEnabled && !isDiscovering)
    237                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
    238         menu.add(Menu.NONE, MENU_ID_RENAME_DEVICE, 0, R.string.bluetooth_rename_device)
    239                 .setEnabled(bluetoothIsEnabled)
    240                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
    241         menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files)
    242                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
    243         super.onCreateOptionsMenu(menu, inflater);
    244     }
    245 
    246     @Override
    247     public boolean onOptionsItemSelected(MenuItem item) {
    248         switch (item.getItemId()) {
    249             case MENU_ID_SCAN:
    250                 if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
    251                     MetricsLogger.action(getActivity(), MetricsEvent.ACTION_BLUETOOTH_SCAN);
    252                     startScanning();
    253                 }
    254                 return true;
    255 
    256             case MENU_ID_RENAME_DEVICE:
    257                 MetricsLogger.action(getActivity(), MetricsEvent.ACTION_BLUETOOTH_RENAME);
    258                 new BluetoothNameDialogFragment().show(
    259                         getFragmentManager(), "rename device");
    260                 return true;
    261 
    262             case MENU_ID_SHOW_RECEIVED:
    263                 MetricsLogger.action(getActivity(), MetricsEvent.ACTION_BLUETOOTH_FILES);
    264                 Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
    265                 getActivity().sendBroadcast(intent);
    266                 return true;
    267         }
    268         return super.onOptionsItemSelected(item);
    269     }
    270 
    271     private void startScanning() {
    272         if (isUiRestricted()) {
    273             return;
    274         }
    275 
    276         if (!mAvailableDevicesCategoryIsPresent) {
    277             getPreferenceScreen().addPreference(mAvailableDevicesCategory);
    278             mAvailableDevicesCategoryIsPresent = true;
    279         }
    280 
    281         if (mAvailableDevicesCategory != null) {
    282             setDeviceListGroup(mAvailableDevicesCategory);
    283             removeAllDevices();
    284         }
    285 
    286         mLocalManager.getCachedDeviceManager().clearNonBondedDevices();
    287         mAvailableDevicesCategory.removeAll();
    288         mInitialScanStarted = true;
    289         mLocalAdapter.startScanning(true);
    290     }
    291 
    292     @Override
    293     void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
    294         mLocalAdapter.stopScanning();
    295         super.onDevicePreferenceClick(btPreference);
    296     }
    297 
    298     private void addDeviceCategory(PreferenceGroup preferenceGroup, int titleId,
    299             BluetoothDeviceFilter.Filter filter, boolean addCachedDevices) {
    300         cacheRemoveAllPrefs(preferenceGroup);
    301         preferenceGroup.setTitle(titleId);
    302         setFilter(filter);
    303         setDeviceListGroup(preferenceGroup);
    304         if (addCachedDevices) {
    305             addCachedDevices();
    306         }
    307         preferenceGroup.setEnabled(true);
    308         removeCachedPrefs(preferenceGroup);
    309     }
    310 
    311     private void updateContent(int bluetoothState) {
    312         final PreferenceScreen preferenceScreen = getPreferenceScreen();
    313         int messageId = 0;
    314 
    315         switch (bluetoothState) {
    316             case BluetoothAdapter.STATE_ON:
    317                 mDevicePreferenceMap.clear();
    318 
    319                 if (isUiRestricted()) {
    320                     messageId = R.string.bluetooth_empty_list_user_restricted;
    321                     break;
    322                 }
    323                 getPreferenceScreen().removeAll();
    324                 getPreferenceScreen().addPreference(mPairedDevicesCategory);
    325                 getPreferenceScreen().addPreference(mAvailableDevicesCategory);
    326                 getPreferenceScreen().addPreference(mMyDevicePreference);
    327 
    328                 // Paired devices category
    329                 addDeviceCategory(mPairedDevicesCategory,
    330                         R.string.bluetooth_preference_paired_devices,
    331                         BluetoothDeviceFilter.BONDED_DEVICE_FILTER, true);
    332                 int numberOfPairedDevices = mPairedDevicesCategory.getPreferenceCount();
    333 
    334                 if (isUiRestricted() || numberOfPairedDevices <= 0) {
    335                     if (preferenceScreen.findPreference(KEY_PAIRED_DEVICES) != null) {
    336                         preferenceScreen.removePreference(mPairedDevicesCategory);
    337                     }
    338                 } else {
    339                     if (preferenceScreen.findPreference(KEY_PAIRED_DEVICES) == null) {
    340                         preferenceScreen.addPreference(mPairedDevicesCategory);
    341                     }
    342                 }
    343 
    344                 // Available devices category
    345                 addDeviceCategory(mAvailableDevicesCategory,
    346                         R.string.bluetooth_preference_found_devices,
    347                         BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER, mInitialScanStarted);
    348 
    349                 if (!mInitialScanStarted) {
    350                     startScanning();
    351                 }
    352 
    353                 final Resources res = getResources();
    354                 final Locale locale = res.getConfiguration().getLocales().get(0);
    355                 final BidiFormatter bidiFormatter = BidiFormatter.getInstance(locale);
    356                 mMyDevicePreference.setSummary(res.getString(
    357                             R.string.bluetooth_is_visible_message,
    358                             bidiFormatter.unicodeWrap(mLocalAdapter.getName())));
    359 
    360                 getActivity().invalidateOptionsMenu();
    361 
    362                 // mLocalAdapter.setScanMode is internally synchronized so it is okay for multiple
    363                 // threads to execute.
    364                 if (mInitiateDiscoverable) {
    365                     // Make the device visible to other devices.
    366                     mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
    367                     mInitiateDiscoverable = false;
    368                 }
    369                 return; // not break
    370 
    371             case BluetoothAdapter.STATE_TURNING_OFF:
    372                 messageId = R.string.bluetooth_turning_off;
    373                 break;
    374 
    375             case BluetoothAdapter.STATE_OFF:
    376                 setOffMessage();
    377                 if (isUiRestricted()) {
    378                     messageId = R.string.bluetooth_empty_list_user_restricted;
    379                 }
    380                 break;
    381 
    382             case BluetoothAdapter.STATE_TURNING_ON:
    383                 messageId = R.string.bluetooth_turning_on;
    384                 mInitialScanStarted = false;
    385                 break;
    386         }
    387 
    388         setDeviceListGroup(preferenceScreen);
    389         removeAllDevices();
    390         if (messageId != 0) {
    391             getEmptyTextView().setText(messageId);
    392         }
    393         if (!isUiRestricted()) {
    394             getActivity().invalidateOptionsMenu();
    395         }
    396     }
    397 
    398     private void setOffMessage() {
    399         final TextView emptyView = getEmptyTextView();
    400         if (emptyView == null) {
    401             return;
    402         }
    403         final CharSequence briefText = getText(R.string.bluetooth_empty_list_bluetooth_off);
    404 
    405         final ContentResolver resolver = getActivity().getContentResolver();
    406         final boolean bleScanningMode = Settings.Global.getInt(
    407                 resolver, Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
    408 
    409         if (!bleScanningMode) {
    410             // Show only the brief text if the scanning mode has been turned off.
    411             emptyView.setText(briefText, TextView.BufferType.SPANNABLE);
    412         } else {
    413             final StringBuilder contentBuilder = new StringBuilder();
    414             contentBuilder.append(briefText);
    415             contentBuilder.append("\n\n");
    416             contentBuilder.append(getText(R.string.ble_scan_notify_text));
    417             LinkifyUtils.linkify(emptyView, contentBuilder, new LinkifyUtils.OnClickListener() {
    418                 @Override
    419                 public void onClick() {
    420                     final SettingsActivity activity =
    421                             (SettingsActivity) BluetoothSettings.this.getActivity();
    422                     activity.startPreferencePanel(ScanningSettings.class.getName(), null,
    423                             R.string.location_scanning_screen_title, null, null, 0);
    424                 }
    425             });
    426         }
    427         getPreferenceScreen().removeAll();
    428         Spannable boldSpan = (Spannable) emptyView.getText();
    429         boldSpan.setSpan(
    430                 new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_Medium), 0,
    431                 briefText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    432     }
    433 
    434     @Override
    435     public void onBluetoothStateChanged(int bluetoothState) {
    436         super.onBluetoothStateChanged(bluetoothState);
    437         // If BT is turned off/on staying in the same BT Settings screen
    438         // discoverability to be set again
    439         if (BluetoothAdapter.STATE_ON == bluetoothState)
    440             mInitiateDiscoverable = true;
    441         updateContent(bluetoothState);
    442     }
    443 
    444     @Override
    445     public void onScanningStateChanged(boolean started) {
    446         super.onScanningStateChanged(started);
    447         // Update options' enabled state
    448         if (getActivity() != null) {
    449             getActivity().invalidateOptionsMenu();
    450         }
    451     }
    452 
    453     @Override
    454     public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
    455         setDeviceListGroup(getPreferenceScreen());
    456         removeAllDevices();
    457         updateContent(mLocalAdapter.getBluetoothState());
    458     }
    459 
    460     private final View.OnClickListener mDeviceProfilesListener = new View.OnClickListener() {
    461         @Override
    462         public void onClick(View v) {
    463             // User clicked on advanced options icon for a device in the list
    464             if (!(v.getTag() instanceof CachedBluetoothDevice)) {
    465                 Log.w(TAG, "onClick() called for other View: " + v);
    466                 return;
    467             }
    468 
    469             final CachedBluetoothDevice device = (CachedBluetoothDevice) v.getTag();
    470             Bundle args = new Bundle();
    471             args.putString(DeviceProfilesSettings.ARG_DEVICE_ADDRESS,
    472                     device.getDevice().getAddress());
    473             DeviceProfilesSettings profileSettings = new DeviceProfilesSettings();
    474             profileSettings.setArguments(args);
    475             profileSettings.show(getFragmentManager(),
    476                     DeviceProfilesSettings.class.getSimpleName());
    477         }
    478     };
    479 
    480     /**
    481      * Add a listener, which enables the advanced settings icon.
    482      * @param preference the newly added preference
    483      */
    484     @Override
    485     void initDevicePreference(BluetoothDevicePreference preference) {
    486         CachedBluetoothDevice cachedDevice = preference.getCachedDevice();
    487         if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
    488             // Only paired device have an associated advanced settings screen
    489             preference.setOnSettingsClickListener(mDeviceProfilesListener);
    490         }
    491     }
    492 
    493     @Override
    494     protected int getHelpResource() {
    495         return R.string.help_url_bluetooth;
    496     }
    497 
    498     private static class SummaryProvider
    499             implements SummaryLoader.SummaryProvider, BluetoothCallback {
    500 
    501         private final LocalBluetoothManager mBluetoothManager;
    502         private final Context mContext;
    503         private final SummaryLoader mSummaryLoader;
    504 
    505         private boolean mEnabled;
    506         private boolean mConnected;
    507 
    508         public SummaryProvider(Context context, SummaryLoader summaryLoader) {
    509             mBluetoothManager = Utils.getLocalBtManager(context);
    510             mContext = context;
    511             mSummaryLoader = summaryLoader;
    512         }
    513 
    514         @Override
    515         public void setListening(boolean listening) {
    516             BluetoothAdapter defaultAdapter = BluetoothAdapter.getDefaultAdapter();
    517             if (defaultAdapter == null) return;
    518             if (listening) {
    519                 mEnabled = defaultAdapter.isEnabled();
    520                 mConnected =
    521                         defaultAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED;
    522                 mSummaryLoader.setSummary(this, getSummary());
    523                 mBluetoothManager.getEventManager().registerCallback(this);
    524             } else {
    525                 mBluetoothManager.getEventManager().unregisterCallback(this);
    526             }
    527         }
    528 
    529         private CharSequence getSummary() {
    530             return mContext.getString(!mEnabled ? R.string.bluetooth_disabled
    531                     : mConnected ? R.string.bluetooth_connected
    532                     : R.string.bluetooth_disconnected);
    533         }
    534 
    535         @Override
    536         public void onBluetoothStateChanged(int bluetoothState) {
    537             mEnabled = bluetoothState == BluetoothAdapter.STATE_ON;
    538             mSummaryLoader.setSummary(this, getSummary());
    539         }
    540 
    541         @Override
    542         public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
    543             mConnected = state == BluetoothAdapter.STATE_CONNECTED;
    544             mSummaryLoader.setSummary(this, getSummary());
    545         }
    546 
    547         @Override
    548         public void onScanningStateChanged(boolean started) {
    549 
    550         }
    551 
    552         @Override
    553         public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
    554 
    555         }
    556 
    557         @Override
    558         public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
    559 
    560         }
    561 
    562         @Override
    563         public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
    564 
    565         }
    566     }
    567 
    568     public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
    569             = new SummaryLoader.SummaryProviderFactory() {
    570         @Override
    571         public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
    572                                                                    SummaryLoader summaryLoader) {
    573             return new SummaryProvider(activity, summaryLoader);
    574         }
    575     };
    576 
    577     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
    578         new BaseSearchIndexProvider() {
    579             @Override
    580             public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
    581 
    582                 final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
    583 
    584                 final Resources res = context.getResources();
    585 
    586                 // Add fragment title
    587                 SearchIndexableRaw data = new SearchIndexableRaw(context);
    588                 data.title = res.getString(R.string.bluetooth_settings);
    589                 data.screenTitle = res.getString(R.string.bluetooth_settings);
    590                 result.add(data);
    591 
    592                 // Add cached paired BT devices
    593                 LocalBluetoothManager lbtm = Utils.getLocalBtManager(context);
    594                 // LocalBluetoothManager.getInstance can return null if the device does not
    595                 // support bluetooth (e.g. the emulator).
    596                 if (lbtm != null) {
    597                     Set<BluetoothDevice> bondedDevices =
    598                             lbtm.getBluetoothAdapter().getBondedDevices();
    599 
    600                     for (BluetoothDevice device : bondedDevices) {
    601                         data = new SearchIndexableRaw(context);
    602                         data.title = device.getName();
    603                         data.screenTitle = res.getString(R.string.bluetooth_settings);
    604                         data.enabled = enabled;
    605                         result.add(data);
    606                     }
    607                 }
    608                 return result;
    609             }
    610         };
    611 }
    612