• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
BluetoothSettings()130     public BluetoothSettings() {
131         super(DISALLOW_CONFIG_BLUETOOTH);
132         mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
133     }
134 
135     @Override
getMetricsCategory()136     protected int getMetricsCategory() {
137         return MetricsEvent.BLUETOOTH;
138     }
139 
140     @Override
onActivityCreated(Bundle savedInstanceState)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
onDestroyView()154     public void onDestroyView() {
155         super.onDestroyView();
156 
157         mBluetoothEnabler.teardownSwitchBar();
158     }
159 
160     @Override
addPreferencesForActivity()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
onResume()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
onPause()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
onCreateOptionsMenu(Menu menu, MenuInflater inflater)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
onOptionsItemSelected(MenuItem item)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 
startScanning()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
onDevicePreferenceClick(BluetoothDevicePreference btPreference)293     void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
294         mLocalAdapter.stopScanning();
295         super.onDevicePreferenceClick(btPreference);
296     }
297 
addDeviceCategory(PreferenceGroup preferenceGroup, int titleId, BluetoothDeviceFilter.Filter filter, boolean addCachedDevices)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 
updateContent(int bluetoothState)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 
setOffMessage()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
onBluetoothStateChanged(int bluetoothState)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
onScanningStateChanged(boolean started)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
onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState)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
initDevicePreference(BluetoothDevicePreference preference)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
getHelpResource()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 
SummaryProvider(Context context, SummaryLoader summaryLoader)508         public SummaryProvider(Context context, SummaryLoader summaryLoader) {
509             mBluetoothManager = Utils.getLocalBtManager(context);
510             mContext = context;
511             mSummaryLoader = summaryLoader;
512         }
513 
514         @Override
setListening(boolean listening)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 
getSummary()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
onBluetoothStateChanged(int bluetoothState)536         public void onBluetoothStateChanged(int bluetoothState) {
537             mEnabled = bluetoothState == BluetoothAdapter.STATE_ON;
538             mSummaryLoader.setSummary(this, getSummary());
539         }
540 
541         @Override
onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state)542         public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
543             mConnected = state == BluetoothAdapter.STATE_CONNECTED;
544             mSummaryLoader.setSummary(this, getSummary());
545         }
546 
547         @Override
onScanningStateChanged(boolean started)548         public void onScanningStateChanged(boolean started) {
549 
550         }
551 
552         @Override
onDeviceAdded(CachedBluetoothDevice cachedDevice)553         public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
554 
555         }
556 
557         @Override
onDeviceDeleted(CachedBluetoothDevice cachedDevice)558         public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
559 
560         }
561 
562         @Override
onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState)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