• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 android.bluetooth;
18 
19 import android.annotation.SdkConstant;
20 import android.annotation.SdkConstant.SdkConstantType;
21 import android.content.Context;
22 import android.os.Binder;
23 import android.os.Handler;
24 import android.os.IBinder;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.os.ParcelUuid;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 import android.util.Log;
31 import android.util.Pair;
32 
33 import java.io.IOException;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.HashSet;
37 import java.util.LinkedList;
38 import java.util.Random;
39 import java.util.Set;
40 import java.util.UUID;
41 
42 /**
43  * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
44  * lets you perform fundamental Bluetooth tasks, such as initiate
45  * device discovery, query a list of bonded (paired) devices,
46  * instantiate a {@link BluetoothDevice} using a known MAC address, and create
47  * a {@link BluetoothServerSocket} to listen for connection requests from other
48  * devices.
49  *
50  * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
51  * adapter, call the static {@link #getDefaultAdapter} method.
52  * Fundamentally, this is your starting point for all
53  * Bluetooth actions. Once you have the local adapter, you can get a set of
54  * {@link BluetoothDevice} objects representing all paired devices with
55  * {@link #getBondedDevices()}; start device discovery with
56  * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
57  * listen for incoming connection requests with
58  * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}.
59  *
60  * <p class="note"><strong>Note:</strong>
61  * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
62  * permission and some also require the
63  * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
64  *
65  * <div class="special reference">
66  * <h3>Developer Guides</h3>
67  * <p>For more information about using Bluetooth, read the
68  * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p>
69  * </div>
70  *
71  * {@see BluetoothDevice}
72  * {@see BluetoothServerSocket}
73  */
74 public final class BluetoothAdapter {
75     private static final String TAG = "BluetoothAdapter";
76     private static final boolean DBG = false;
77 
78     /**
79      * Sentinel error value for this class. Guaranteed to not equal any other
80      * integer constant in this class. Provided as a convenience for functions
81      * that require a sentinel error value, for example:
82      * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
83      * BluetoothAdapter.ERROR)</code>
84      */
85     public static final int ERROR = Integer.MIN_VALUE;
86 
87     /**
88      * Broadcast Action: The state of the local Bluetooth adapter has been
89      * changed.
90      * <p>For example, Bluetooth has been turned on or off.
91      * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
92      * #EXTRA_PREVIOUS_STATE} containing the new and old states
93      * respectively.
94      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
95      */
96     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
97     public static final String ACTION_STATE_CHANGED =
98             "android.bluetooth.adapter.action.STATE_CHANGED";
99 
100     /**
101      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
102      * intents to request the current power state. Possible values are:
103      * {@link #STATE_OFF},
104      * {@link #STATE_TURNING_ON},
105      * {@link #STATE_ON},
106      * {@link #STATE_TURNING_OFF},
107      */
108     public static final String EXTRA_STATE =
109             "android.bluetooth.adapter.extra.STATE";
110     /**
111      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
112      * intents to request the previous power state. Possible values are:
113      * {@link #STATE_OFF},
114      * {@link #STATE_TURNING_ON},
115      * {@link #STATE_ON},
116      * {@link #STATE_TURNING_OFF},
117      */
118     public static final String EXTRA_PREVIOUS_STATE =
119             "android.bluetooth.adapter.extra.PREVIOUS_STATE";
120 
121     /**
122      * Indicates the local Bluetooth adapter is off.
123      */
124     public static final int STATE_OFF = 10;
125     /**
126      * Indicates the local Bluetooth adapter is turning on. However local
127      * clients should wait for {@link #STATE_ON} before attempting to
128      * use the adapter.
129      */
130     public static final int STATE_TURNING_ON = 11;
131     /**
132      * Indicates the local Bluetooth adapter is on, and ready for use.
133      */
134     public static final int STATE_ON = 12;
135     /**
136      * Indicates the local Bluetooth adapter is turning off. Local clients
137      * should immediately attempt graceful disconnection of any remote links.
138      */
139     public static final int STATE_TURNING_OFF = 13;
140 
141     /**
142      * Activity Action: Show a system activity that requests discoverable mode.
143      * This activity will also request the user to turn on Bluetooth if it
144      * is not currently enabled.
145      * <p>Discoverable mode is equivalent to {@link
146      * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see
147      * this Bluetooth adapter when they perform a discovery.
148      * <p>For privacy, Android is not discoverable by default.
149      * <p>The sender of this Intent can optionally use extra field {@link
150      * #EXTRA_DISCOVERABLE_DURATION} to request the duration of
151      * discoverability. Currently the default duration is 120 seconds, and
152      * maximum duration is capped at 300 seconds for each request.
153      * <p>Notification of the result of this activity is posted using the
154      * {@link android.app.Activity#onActivityResult} callback. The
155      * <code>resultCode</code>
156      * will be the duration (in seconds) of discoverability or
157      * {@link android.app.Activity#RESULT_CANCELED} if the user rejected
158      * discoverability or an error has occurred.
159      * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
160      * for global notification whenever the scan mode changes. For example, an
161      * application can be notified when the device has ended discoverability.
162      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
163      */
164     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
165     public static final String ACTION_REQUEST_DISCOVERABLE =
166             "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
167 
168     /**
169      * Used as an optional int extra field in {@link
170      * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration
171      * for discoverability in seconds. The current default is 120 seconds, and
172      * requests over 300 seconds will be capped. These values could change.
173      */
174     public static final String EXTRA_DISCOVERABLE_DURATION =
175             "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
176 
177     /**
178      * Activity Action: Show a system activity that allows the user to turn on
179      * Bluetooth.
180      * <p>This system activity will return once Bluetooth has completed turning
181      * on, or the user has decided not to turn Bluetooth on.
182      * <p>Notification of the result of this activity is posted using the
183      * {@link android.app.Activity#onActivityResult} callback. The
184      * <code>resultCode</code>
185      * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
186      * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
187      * has rejected the request or an error has occurred.
188      * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
189      * for global notification whenever Bluetooth is turned on or off.
190      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
191      */
192     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
193     public static final String ACTION_REQUEST_ENABLE =
194             "android.bluetooth.adapter.action.REQUEST_ENABLE";
195 
196     /**
197      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
198      * has changed.
199      * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
200      * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
201      * respectively.
202      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
203      */
204     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
205     public static final String ACTION_SCAN_MODE_CHANGED =
206             "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
207 
208     /**
209      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
210      * intents to request the current scan mode. Possible values are:
211      * {@link #SCAN_MODE_NONE},
212      * {@link #SCAN_MODE_CONNECTABLE},
213      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
214      */
215     public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
216     /**
217      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
218      * intents to request the previous scan mode. Possible values are:
219      * {@link #SCAN_MODE_NONE},
220      * {@link #SCAN_MODE_CONNECTABLE},
221      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
222      */
223     public static final String EXTRA_PREVIOUS_SCAN_MODE =
224             "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
225 
226     /**
227      * Indicates that both inquiry scan and page scan are disabled on the local
228      * Bluetooth adapter. Therefore this device is neither discoverable
229      * nor connectable from remote Bluetooth devices.
230      */
231     public static final int SCAN_MODE_NONE = 20;
232     /**
233      * Indicates that inquiry scan is disabled, but page scan is enabled on the
234      * local Bluetooth adapter. Therefore this device is not discoverable from
235      * remote Bluetooth devices, but is connectable from remote devices that
236      * have previously discovered this device.
237      */
238     public static final int SCAN_MODE_CONNECTABLE = 21;
239     /**
240      * Indicates that both inquiry scan and page scan are enabled on the local
241      * Bluetooth adapter. Therefore this device is both discoverable and
242      * connectable from remote Bluetooth devices.
243      */
244     public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
245 
246 
247     /**
248      * Broadcast Action: The local Bluetooth adapter has started the remote
249      * device discovery process.
250      * <p>This usually involves an inquiry scan of about 12 seconds, followed
251      * by a page scan of each new device to retrieve its Bluetooth name.
252      * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
253      * remote Bluetooth devices are found.
254      * <p>Device discovery is a heavyweight procedure. New connections to
255      * remote Bluetooth devices should not be attempted while discovery is in
256      * progress, and existing connections will experience limited bandwidth
257      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
258      * discovery.
259      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
260      */
261     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
262     public static final String ACTION_DISCOVERY_STARTED =
263             "android.bluetooth.adapter.action.DISCOVERY_STARTED";
264     /**
265      * Broadcast Action: The local Bluetooth adapter has finished the device
266      * discovery process.
267      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
268      */
269     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
270     public static final String ACTION_DISCOVERY_FINISHED =
271             "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
272 
273     /**
274      * Broadcast Action: The local Bluetooth adapter has changed its friendly
275      * Bluetooth name.
276      * <p>This name is visible to remote Bluetooth devices.
277      * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
278      * the name.
279      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
280      */
281     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
282     public static final String ACTION_LOCAL_NAME_CHANGED =
283             "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
284     /**
285      * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
286      * intents to request the local Bluetooth name.
287      */
288     public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
289 
290     /**
291      * Intent used to broadcast the change in connection state of the local
292      * Bluetooth adapter to a profile of the remote device. When the adapter is
293      * not connected to any profiles of any remote devices and it attempts a
294      * connection to a profile this intent will sent. Once connected, this intent
295      * will not be sent for any more connection attempts to any profiles of any
296      * remote device. When the adapter disconnects from the last profile its
297      * connected to of any remote device, this intent will be sent.
298      *
299      * <p> This intent is useful for applications that are only concerned about
300      * whether the local adapter is connected to any profile of any device and
301      * are not really concerned about which profile. For example, an application
302      * which displays an icon to display whether Bluetooth is connected or not
303      * can use this intent.
304      *
305      * <p>This intent will have 3 extras:
306      * {@link #EXTRA_CONNECTION_STATE} - The current connection state.
307      * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state.
308      * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
309      *
310      * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE}
311      * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
312      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
313      *
314      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
315      */
316     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
317     public static final String ACTION_CONNECTION_STATE_CHANGED =
318         "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
319 
320     /**
321      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
322      *
323      * This extra represents the current connection state.
324      */
325     public static final String EXTRA_CONNECTION_STATE =
326         "android.bluetooth.adapter.extra.CONNECTION_STATE";
327 
328     /**
329      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
330      *
331      * This extra represents the previous connection state.
332      */
333     public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
334           "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
335 
336     /** The profile is in disconnected state */
337     public static final int STATE_DISCONNECTED  = 0;
338     /** The profile is in connecting state */
339     public static final int STATE_CONNECTING    = 1;
340     /** The profile is in connected state */
341     public static final int STATE_CONNECTED     = 2;
342     /** The profile is in disconnecting state */
343     public static final int STATE_DISCONNECTING = 3;
344 
345     /** @hide */
346     public static final String BLUETOOTH_SERVICE = "bluetooth";
347 
348     private static final int ADDRESS_LENGTH = 17;
349 
350     /**
351      * Lazily initialized singleton. Guaranteed final after first object
352      * constructed.
353      */
354     private static BluetoothAdapter sAdapter;
355 
356     private final IBluetooth mService;
357 
358     private Handler mServiceRecordHandler;
359 
360     /**
361      * Get a handle to the default local Bluetooth adapter.
362      * <p>Currently Android only supports one Bluetooth adapter, but the API
363      * could be extended to support more. This will always return the default
364      * adapter.
365      * @return the default local adapter, or null if Bluetooth is not supported
366      *         on this hardware platform
367      */
getDefaultAdapter()368     public static synchronized BluetoothAdapter getDefaultAdapter() {
369         if (sAdapter == null) {
370             IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
371             if (b != null) {
372                 IBluetooth service = IBluetooth.Stub.asInterface(b);
373                 sAdapter = new BluetoothAdapter(service);
374             }
375         }
376         return sAdapter;
377     }
378 
379     /**
380      * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
381      * @hide
382      */
BluetoothAdapter(IBluetooth service)383     public BluetoothAdapter(IBluetooth service) {
384         if (service == null) {
385             throw new IllegalArgumentException("service is null");
386         }
387         mService = service;
388         mServiceRecordHandler = null;
389     }
390 
391     /**
392      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
393      * address.
394      * <p>Valid Bluetooth hardware addresses must be upper case, in a format
395      * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
396      * available to validate a Bluetooth address.
397      * <p>A {@link BluetoothDevice} will always be returned for a valid
398      * hardware address, even if this adapter has never seen that device.
399      *
400      * @param address valid Bluetooth MAC address
401      * @throws IllegalArgumentException if address is invalid
402      */
getRemoteDevice(String address)403     public BluetoothDevice getRemoteDevice(String address) {
404         return new BluetoothDevice(address);
405     }
406 
407     /**
408      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
409      * address.
410      * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method
411      * expects the address in network byte order (MSB first).
412      * <p>A {@link BluetoothDevice} will always be returned for a valid
413      * hardware address, even if this adapter has never seen that device.
414      *
415      * @param address Bluetooth MAC address (6 bytes)
416      * @throws IllegalArgumentException if address is invalid
417      */
getRemoteDevice(byte[] address)418     public BluetoothDevice getRemoteDevice(byte[] address) {
419         if (address == null || address.length != 6) {
420             throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
421         }
422         return new BluetoothDevice(String.format("%02X:%02X:%02X:%02X:%02X:%02X",
423                 address[0], address[1], address[2], address[3], address[4], address[5]));
424     }
425 
426     /**
427      * Return true if Bluetooth is currently enabled and ready for use.
428      * <p>Equivalent to:
429      * <code>getBluetoothState() == STATE_ON</code>
430      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
431      *
432      * @return true if the local adapter is turned on
433      */
isEnabled()434     public boolean isEnabled() {
435         try {
436             return mService.isEnabled();
437         } catch (RemoteException e) {Log.e(TAG, "", e);}
438         return false;
439     }
440 
441     /**
442      * Get the current state of the local Bluetooth adapter.
443      * <p>Possible return values are
444      * {@link #STATE_OFF},
445      * {@link #STATE_TURNING_ON},
446      * {@link #STATE_ON},
447      * {@link #STATE_TURNING_OFF}.
448      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
449      *
450      * @return current state of Bluetooth adapter
451      */
getState()452     public int getState() {
453         try {
454             return mService.getBluetoothState();
455         } catch (RemoteException e) {Log.e(TAG, "", e);}
456         return STATE_OFF;
457     }
458 
459     /**
460      * Turn on the local Bluetooth adapter&mdash;do not use without explicit
461      * user action to turn on Bluetooth.
462      * <p>This powers on the underlying Bluetooth hardware, and starts all
463      * Bluetooth system services.
464      * <p class="caution"><strong>Bluetooth should never be enabled without
465      * direct user consent</strong>. If you want to turn on Bluetooth in order
466      * to create a wireless connection, you should use the {@link
467      * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
468      * user permission to turn on Bluetooth. The {@link #enable()} method is
469      * provided only for applications that include a user interface for changing
470      * system settings, such as a "power manager" app.</p>
471      * <p>This is an asynchronous call: it will return immediately, and
472      * clients should listen for {@link #ACTION_STATE_CHANGED}
473      * to be notified of subsequent adapter state changes. If this call returns
474      * true, then the adapter state will immediately transition from {@link
475      * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
476      * later transition to either {@link #STATE_OFF} or {@link
477      * #STATE_ON}. If this call returns false then there was an
478      * immediate problem that will prevent the adapter from being turned on -
479      * such as Airplane mode, or the adapter is already turned on.
480      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
481      * permission
482      *
483      * @return true to indicate adapter startup has begun, or false on
484      *         immediate error
485      */
enable()486     public boolean enable() {
487         try {
488             return mService.enable();
489         } catch (RemoteException e) {Log.e(TAG, "", e);}
490         return false;
491     }
492 
493     /**
494      * Turn off the local Bluetooth adapter&mdash;do not use without explicit
495      * user action to turn off Bluetooth.
496      * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
497      * system services, and powers down the underlying Bluetooth hardware.
498      * <p class="caution"><strong>Bluetooth should never be disabled without
499      * direct user consent</strong>. The {@link #disable()} method is
500      * provided only for applications that include a user interface for changing
501      * system settings, such as a "power manager" app.</p>
502      * <p>This is an asynchronous call: it will return immediately, and
503      * clients should listen for {@link #ACTION_STATE_CHANGED}
504      * to be notified of subsequent adapter state changes. If this call returns
505      * true, then the adapter state will immediately transition from {@link
506      * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
507      * later transition to either {@link #STATE_OFF} or {@link
508      * #STATE_ON}. If this call returns false then there was an
509      * immediate problem that will prevent the adapter from being turned off -
510      * such as the adapter already being turned off.
511      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
512      * permission
513      *
514      * @return true to indicate adapter shutdown has begun, or false on
515      *         immediate error
516      */
disable()517     public boolean disable() {
518         try {
519             return mService.disable(true);
520         } catch (RemoteException e) {Log.e(TAG, "", e);}
521         return false;
522     }
523 
524     /**
525      * Returns the hardware address of the local Bluetooth adapter.
526      * <p>For example, "00:11:22:AA:BB:CC".
527      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
528      *
529      * @return Bluetooth hardware address as string
530      */
getAddress()531     public String getAddress() {
532         try {
533             return mService.getAddress();
534         } catch (RemoteException e) {Log.e(TAG, "", e);}
535         return null;
536     }
537 
538     /**
539      * Get the friendly Bluetooth name of the local Bluetooth adapter.
540      * <p>This name is visible to remote Bluetooth devices.
541      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
542      *
543      * @return the Bluetooth name, or null on error
544      */
getName()545     public String getName() {
546         try {
547             return mService.getName();
548         } catch (RemoteException e) {Log.e(TAG, "", e);}
549         return null;
550     }
551 
552     /**
553      * Get the UUIDs supported by the local Bluetooth adapter.
554      *
555      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
556      *
557      * @return the UUIDs supported by the local Bluetooth Adapter.
558      * @hide
559      */
getUuids()560     public ParcelUuid[] getUuids() {
561         if (getState() != STATE_ON) return null;
562         try {
563             return mService.getUuids();
564         } catch (RemoteException e) {Log.e(TAG, "", e);}
565         return null;
566     }
567 
568     /**
569      * Set the friendly Bluetooth name of the local Bluetooth adapter.
570      * <p>This name is visible to remote Bluetooth devices.
571      * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
572      * encoding, although many remote devices can only display the first
573      * 40 characters, and some may be limited to just 20.
574      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
575      * will return false. After turning on Bluetooth,
576      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
577      * to get the updated value.
578      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
579      *
580      * @param name a valid Bluetooth name
581      * @return     true if the name was set, false otherwise
582      */
setName(String name)583     public boolean setName(String name) {
584         if (getState() != STATE_ON) return false;
585         try {
586             return mService.setName(name);
587         } catch (RemoteException e) {Log.e(TAG, "", e);}
588         return false;
589     }
590 
591     /**
592      * Get the current Bluetooth scan mode of the local Bluetooth adapter.
593      * <p>The Bluetooth scan mode determines if the local adapter is
594      * connectable and/or discoverable from remote Bluetooth devices.
595      * <p>Possible values are:
596      * {@link #SCAN_MODE_NONE},
597      * {@link #SCAN_MODE_CONNECTABLE},
598      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
599      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
600      * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
601      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
602      * to get the updated value.
603      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
604      *
605      * @return scan mode
606      */
getScanMode()607     public int getScanMode() {
608         if (getState() != STATE_ON) return SCAN_MODE_NONE;
609         try {
610             return mService.getScanMode();
611         } catch (RemoteException e) {Log.e(TAG, "", e);}
612         return SCAN_MODE_NONE;
613     }
614 
615     /**
616      * Set the Bluetooth scan mode of the local Bluetooth adapter.
617      * <p>The Bluetooth scan mode determines if the local adapter is
618      * connectable and/or discoverable from remote Bluetooth devices.
619      * <p>For privacy reasons, discoverable mode is automatically turned off
620      * after <code>duration</code> seconds. For example, 120 seconds should be
621      * enough for a remote device to initiate and complete its discovery
622      * process.
623      * <p>Valid scan mode values are:
624      * {@link #SCAN_MODE_NONE},
625      * {@link #SCAN_MODE_CONNECTABLE},
626      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
627      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
628      * will return false. After turning on Bluetooth,
629      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
630      * to get the updated value.
631      * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
632      * <p>Applications cannot set the scan mode. They should use
633      * <code>startActivityForResult(
634      * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
635      * </code>instead.
636      *
637      * @param mode valid scan mode
638      * @param duration time in seconds to apply scan mode, only used for
639      *                 {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
640      * @return     true if the scan mode was set, false otherwise
641      * @hide
642      */
setScanMode(int mode, int duration)643     public boolean setScanMode(int mode, int duration) {
644         if (getState() != STATE_ON) return false;
645         try {
646             return mService.setScanMode(mode, duration);
647         } catch (RemoteException e) {Log.e(TAG, "", e);}
648         return false;
649     }
650 
651     /** @hide */
setScanMode(int mode)652     public boolean setScanMode(int mode) {
653         if (getState() != STATE_ON) return false;
654         return setScanMode(mode, 120);
655     }
656 
657     /** @hide */
getDiscoverableTimeout()658     public int getDiscoverableTimeout() {
659         if (getState() != STATE_ON) return -1;
660         try {
661             return mService.getDiscoverableTimeout();
662         } catch (RemoteException e) {Log.e(TAG, "", e);}
663         return -1;
664     }
665 
666     /** @hide */
setDiscoverableTimeout(int timeout)667     public void setDiscoverableTimeout(int timeout) {
668         if (getState() != STATE_ON) return;
669         try {
670             mService.setDiscoverableTimeout(timeout);
671         } catch (RemoteException e) {Log.e(TAG, "", e);}
672     }
673 
674     /**
675      * Start the remote device discovery process.
676      * <p>The discovery process usually involves an inquiry scan of about 12
677      * seconds, followed by a page scan of each new device to retrieve its
678      * Bluetooth name.
679      * <p>This is an asynchronous call, it will return immediately. Register
680      * for {@link #ACTION_DISCOVERY_STARTED} and {@link
681      * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
682      * discovery starts and completes. Register for {@link
683      * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
684      * are found.
685      * <p>Device discovery is a heavyweight procedure. New connections to
686      * remote Bluetooth devices should not be attempted while discovery is in
687      * progress, and existing connections will experience limited bandwidth
688      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
689      * discovery. Discovery is not managed by the Activity,
690      * but is run as a system service, so an application should always call
691      * {@link BluetoothAdapter#cancelDiscovery()} even if it
692      * did not directly request a discovery, just to be sure.
693      * <p>Device discovery will only find remote devices that are currently
694      * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
695      * not discoverable by default, and need to be entered into a special mode.
696      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
697      * will return false. After turning on Bluetooth,
698      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
699      * to get the updated value.
700      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
701      *
702      * @return true on success, false on error
703      */
startDiscovery()704     public boolean startDiscovery() {
705         if (getState() != STATE_ON) return false;
706         try {
707             return mService.startDiscovery();
708         } catch (RemoteException e) {Log.e(TAG, "", e);}
709         return false;
710     }
711 
712     /**
713      * Cancel the current device discovery process.
714      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
715      * <p>Because discovery is a heavyweight procedure for the Bluetooth
716      * adapter, this method should always be called before attempting to connect
717      * to a remote device with {@link
718      * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
719      * the  Activity, but is run as a system service, so an application should
720      * always call cancel discovery even if it did not directly request a
721      * discovery, just to be sure.
722      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
723      * will return false. After turning on Bluetooth,
724      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
725      * to get the updated value.
726      *
727      * @return true on success, false on error
728      */
cancelDiscovery()729     public boolean cancelDiscovery() {
730         if (getState() != STATE_ON) return false;
731         try {
732             return mService.cancelDiscovery();
733         } catch (RemoteException e) {Log.e(TAG, "", e);}
734         return false;
735     }
736 
737     /**
738      * Return true if the local Bluetooth adapter is currently in the device
739      * discovery process.
740      * <p>Device discovery is a heavyweight procedure. New connections to
741      * remote Bluetooth devices should not be attempted while discovery is in
742      * progress, and existing connections will experience limited bandwidth
743      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
744      * discovery.
745      * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
746      * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
747      * starts or completes.
748      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
749      * will return false. After turning on Bluetooth,
750      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
751      * to get the updated value.
752      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
753      *
754      * @return true if discovering
755      */
isDiscovering()756     public boolean isDiscovering() {
757         if (getState() != STATE_ON) return false;
758         try {
759             return mService.isDiscovering();
760         } catch (RemoteException e) {Log.e(TAG, "", e);}
761         return false;
762     }
763 
764     /**
765      * Return the set of {@link BluetoothDevice} objects that are bonded
766      * (paired) to the local adapter.
767      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
768      * will return an empty set. After turning on Bluetooth,
769      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
770      * to get the updated value.
771      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
772      *
773      * @return unmodifiable set of {@link BluetoothDevice}, or null on error
774      */
getBondedDevices()775     public Set<BluetoothDevice> getBondedDevices() {
776         if (getState() != STATE_ON) {
777             return toDeviceSet(new String[0]);
778         }
779         try {
780             return toDeviceSet(mService.listBonds());
781         } catch (RemoteException e) {Log.e(TAG, "", e);}
782         return null;
783     }
784 
785     /**
786      * Get the current connection state of the local Bluetooth adapter.
787      * This can be used to check whether the local Bluetooth adapter is connected
788      * to any profile of any other remote Bluetooth Device.
789      *
790      * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
791      * intent to get the connection state of the adapter.
792      *
793      * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED},
794      * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
795      *
796      * @hide
797      */
getConnectionState()798     public int getConnectionState() {
799         if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
800         try {
801             return mService.getAdapterConnectionState();
802         } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
803         return BluetoothAdapter.STATE_DISCONNECTED;
804     }
805 
806     /**
807      * Get the current connection state of a profile.
808      * This function can be used to check whether the local Bluetooth adapter
809      * is connected to any remote device for a specific profile.
810      * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
811      * {@link BluetoothProfile#A2DP}.
812      *
813      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
814      *
815      * <p> Return value can be one of
816      * {@link BluetoothProfile#STATE_DISCONNECTED},
817      * {@link BluetoothProfile#STATE_CONNECTING},
818      * {@link BluetoothProfile#STATE_CONNECTED},
819      * {@link BluetoothProfile#STATE_DISCONNECTING}
820      */
getProfileConnectionState(int profile)821     public int getProfileConnectionState(int profile) {
822         if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
823         try {
824             return mService.getProfileConnectionState(profile);
825         } catch (RemoteException e) {
826             Log.e(TAG, "getProfileConnectionState:", e);
827         }
828         return BluetoothProfile.STATE_DISCONNECTED;
829     }
830 
831     /**
832     /**
833      * Picks RFCOMM channels until none are left.
834      * Avoids reserved channels.
835      */
836     private static class RfcommChannelPicker {
837         private static final int[] RESERVED_RFCOMM_CHANNELS =  new int[] {
838             10,  // HFAG
839             11,  // HSAG
840             12,  // OPUSH
841             19,  // PBAP
842         };
843         private static LinkedList<Integer> sChannels;  // master list of non-reserved channels
844         private static Random sRandom;
845 
846         private final LinkedList<Integer> mChannels;  // local list of channels left to try
847 
848         private final UUID mUuid;
849 
RfcommChannelPicker(UUID uuid)850         public RfcommChannelPicker(UUID uuid) {
851             synchronized (RfcommChannelPicker.class) {
852                 if (sChannels == null) {
853                     // lazy initialization of non-reserved rfcomm channels
854                     sChannels = new LinkedList<Integer>();
855                     for (int i = 1; i <= BluetoothSocket.MAX_RFCOMM_CHANNEL; i++) {
856                         sChannels.addLast(new Integer(i));
857                     }
858                     for (int reserved : RESERVED_RFCOMM_CHANNELS) {
859                         sChannels.remove(new Integer(reserved));
860                     }
861                     sRandom = new Random();
862                 }
863                 mChannels = (LinkedList<Integer>)sChannels.clone();
864             }
865             mUuid = uuid;
866         }
867         /* Returns next random channel, or -1 if we're out */
nextChannel()868         public int nextChannel() {
869             if (mChannels.size() == 0) {
870                 return -1;
871             }
872             return mChannels.remove(sRandom.nextInt(mChannels.size()));
873         }
874     }
875 
876     /**
877      * Create a listening, secure RFCOMM Bluetooth socket.
878      * <p>A remote device connecting to this socket will be authenticated and
879      * communication on this socket will be encrypted.
880      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
881      * connections from a listening {@link BluetoothServerSocket}.
882      * <p>Valid RFCOMM channels are in range 1 to 30.
883      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
884      * @param channel RFCOMM channel to listen on
885      * @return a listening RFCOMM BluetoothServerSocket
886      * @throws IOException on error, for example Bluetooth not available, or
887      *                     insufficient permissions, or channel in use.
888      * @hide
889      */
listenUsingRfcommOn(int channel)890     public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
891         BluetoothServerSocket socket = new BluetoothServerSocket(
892                 BluetoothSocket.TYPE_RFCOMM, true, true, channel);
893         int errno = socket.mSocket.bindListen();
894         if (errno != 0) {
895             try {
896                 socket.close();
897             } catch (IOException e) {}
898             socket.mSocket.throwErrnoNative(errno);
899         }
900         return socket;
901     }
902 
903     /**
904      * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
905      * <p>A remote device connecting to this socket will be authenticated and
906      * communication on this socket will be encrypted.
907      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
908      * connections from a listening {@link BluetoothServerSocket}.
909      * <p>The system will assign an unused RFCOMM channel to listen on.
910      * <p>The system will also register a Service Discovery
911      * Protocol (SDP) record with the local SDP server containing the specified
912      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
913      * can use the same UUID to query our SDP server and discover which channel
914      * to connect to. This SDP record will be removed when this socket is
915      * closed, or if this application closes unexpectedly.
916      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
917      * connect to this socket from another device using the same {@link UUID}.
918      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
919      * @param name service name for SDP record
920      * @param uuid uuid for SDP record
921      * @return a listening RFCOMM BluetoothServerSocket
922      * @throws IOException on error, for example Bluetooth not available, or
923      *                     insufficient permissions, or channel in use.
924      */
listenUsingRfcommWithServiceRecord(String name, UUID uuid)925     public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
926             throws IOException {
927         return createNewRfcommSocketAndRecord(name, uuid, true, true);
928     }
929 
930     /**
931      * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
932      * <p>The link key is not required to be authenticated, i.e the communication may be
933      * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
934      * the link will be encrypted, as encryption is mandartory.
935      * For legacy devices (pre Bluetooth 2.1 devices) the link will not
936      * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
937      * encrypted and authenticated communication channel is desired.
938      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
939      * connections from a listening {@link BluetoothServerSocket}.
940      * <p>The system will assign an unused RFCOMM channel to listen on.
941      * <p>The system will also register a Service Discovery
942      * Protocol (SDP) record with the local SDP server containing the specified
943      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
944      * can use the same UUID to query our SDP server and discover which channel
945      * to connect to. This SDP record will be removed when this socket is
946      * closed, or if this application closes unexpectedly.
947      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
948      * connect to this socket from another device using the same {@link UUID}.
949      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
950      * @param name service name for SDP record
951      * @param uuid uuid for SDP record
952      * @return a listening RFCOMM BluetoothServerSocket
953      * @throws IOException on error, for example Bluetooth not available, or
954      *                     insufficient permissions, or channel in use.
955      */
listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)956     public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
957             throws IOException {
958         return createNewRfcommSocketAndRecord(name, uuid, false, false);
959     }
960 
961      /**
962      * Create a listening, encrypted,
963      * RFCOMM Bluetooth socket with Service Record.
964      * <p>The link will be encrypted, but the link key is not required to be authenticated
965      * i.e the communication is vulnerable to Man In the Middle attacks. Use
966      * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
967      * <p> Use this socket if authentication of link key is not possible.
968      * For example, for Bluetooth 2.1 devices, if any of the devices does not have
969      * an input and output capability or just has the ability to display a numeric key,
970      * a secure socket connection is not possible and this socket can be used.
971      * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
972      * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory.
973      * For more details, refer to the Security Model section 5.2 (vol 3) of
974      * Bluetooth Core Specification version 2.1 + EDR.
975      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
976      * connections from a listening {@link BluetoothServerSocket}.
977      * <p>The system will assign an unused RFCOMM channel to listen on.
978      * <p>The system will also register a Service Discovery
979      * Protocol (SDP) record with the local SDP server containing the specified
980      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
981      * can use the same UUID to query our SDP server and discover which channel
982      * to connect to. This SDP record will be removed when this socket is
983      * closed, or if this application closes unexpectedly.
984      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
985      * connect to this socket from another device using the same {@link UUID}.
986      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
987      * @param name service name for SDP record
988      * @param uuid uuid for SDP record
989      * @return a listening RFCOMM BluetoothServerSocket
990      * @throws IOException on error, for example Bluetooth not available, or
991      *                     insufficient permissions, or channel in use.
992      * @hide
993      */
listenUsingEncryptedRfcommWithServiceRecord( String name, UUID uuid)994     public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
995             String name, UUID uuid) throws IOException {
996         return createNewRfcommSocketAndRecord(name, uuid, false, true);
997     }
998 
createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt)999     private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
1000             boolean auth, boolean encrypt) throws IOException {
1001         RfcommChannelPicker picker = new RfcommChannelPicker(uuid);
1002 
1003         BluetoothServerSocket socket;
1004         int channel;
1005         int errno;
1006         while (true) {
1007             channel = picker.nextChannel();
1008 
1009             if (channel == -1) {
1010                 throw new IOException("No available channels");
1011             }
1012 
1013             socket = new BluetoothServerSocket(
1014                     BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel);
1015             errno = socket.mSocket.bindListen();
1016             if (errno == 0) {
1017                 if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel);
1018                 break;  // success
1019             } else if (errno == BluetoothSocket.EADDRINUSE) {
1020                 if (DBG) Log.d(TAG, "RFCOMM channel " + channel + " in use");
1021                 try {
1022                     socket.close();
1023                 } catch (IOException e) {}
1024                 continue;  // try another channel
1025             } else {
1026                 try {
1027                     socket.close();
1028                 } catch (IOException e) {}
1029                 socket.mSocket.throwErrnoNative(errno);  // Exception as a result of bindListen()
1030             }
1031         }
1032 
1033         int handle = -1;
1034         try {
1035             handle = mService.addRfcommServiceRecord(name, new ParcelUuid(uuid), channel,
1036                     new Binder());
1037         } catch (RemoteException e) {Log.e(TAG, "", e);}
1038         if (handle == -1) {
1039             try {
1040                 socket.close();
1041             } catch (IOException e) {}
1042             throw new IOException("Not able to register SDP record for " + name);
1043         }
1044 
1045         if (mServiceRecordHandler == null) {
1046             mServiceRecordHandler = new Handler(Looper.getMainLooper()) {
1047                     public void handleMessage(Message msg) {
1048                         /* handle socket closing */
1049                         int handle = msg.what;
1050                         try {
1051                             if (DBG) Log.d(TAG, "Removing service record " +
1052                                            Integer.toHexString(handle));
1053                             mService.removeServiceRecord(handle);
1054                         } catch (RemoteException e) {Log.e(TAG, "", e);}
1055                     }
1056                 };
1057         }
1058         socket.setCloseHandler(mServiceRecordHandler, handle);
1059         return socket;
1060     }
1061 
1062 
1063     /**
1064      * Construct an unencrypted, unauthenticated, RFCOMM server socket.
1065      * Call #accept to retrieve connections to this socket.
1066      * @return An RFCOMM BluetoothServerSocket
1067      * @throws IOException On error, for example Bluetooth not available, or
1068      *                     insufficient permissions.
1069      * @hide
1070      */
listenUsingInsecureRfcommOn(int port)1071     public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
1072         BluetoothServerSocket socket = new BluetoothServerSocket(
1073                 BluetoothSocket.TYPE_RFCOMM, false, false, port);
1074         int errno = socket.mSocket.bindListen();
1075         if (errno != 0) {
1076             try {
1077                 socket.close();
1078             } catch (IOException e) {}
1079             socket.mSocket.throwErrnoNative(errno);
1080         }
1081         return socket;
1082     }
1083 
1084      /**
1085      * Construct an encrypted, RFCOMM server socket.
1086      * Call #accept to retrieve connections to this socket.
1087      * @return An RFCOMM BluetoothServerSocket
1088      * @throws IOException On error, for example Bluetooth not available, or
1089      *                     insufficient permissions.
1090      * @hide
1091      */
listenUsingEncryptedRfcommOn(int port)1092     public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
1093             throws IOException {
1094         BluetoothServerSocket socket = new BluetoothServerSocket(
1095                 BluetoothSocket.TYPE_RFCOMM, false, true, port);
1096         int errno = socket.mSocket.bindListen();
1097         if (errno != 0) {
1098             try {
1099                 socket.close();
1100             } catch (IOException e) {}
1101             socket.mSocket.throwErrnoNative(errno);
1102         }
1103         return socket;
1104     }
1105 
1106     /**
1107      * Construct a SCO server socket.
1108      * Call #accept to retrieve connections to this socket.
1109      * @return A SCO BluetoothServerSocket
1110      * @throws IOException On error, for example Bluetooth not available, or
1111      *                     insufficient permissions.
1112      * @hide
1113      */
listenUsingScoOn()1114     public static BluetoothServerSocket listenUsingScoOn() throws IOException {
1115         BluetoothServerSocket socket = new BluetoothServerSocket(
1116                 BluetoothSocket.TYPE_SCO, false, false, -1);
1117         int errno = socket.mSocket.bindListen();
1118         if (errno != 0) {
1119             try {
1120                 socket.close();
1121             } catch (IOException e) {}
1122             socket.mSocket.throwErrnoNative(errno);
1123         }
1124         return socket;
1125     }
1126 
1127     /**
1128      * Read the local Out of Band Pairing Data
1129      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1130      *
1131      * @return Pair<byte[], byte[]> of Hash and Randomizer
1132      *
1133      * @hide
1134      */
readOutOfBandData()1135     public Pair<byte[], byte[]> readOutOfBandData() {
1136         if (getState() != STATE_ON) return null;
1137         try {
1138             byte[] hash;
1139             byte[] randomizer;
1140 
1141             byte[] ret = mService.readOutOfBandData();
1142 
1143             if (ret  == null || ret.length != 32) return null;
1144 
1145             hash = Arrays.copyOfRange(ret, 0, 16);
1146             randomizer = Arrays.copyOfRange(ret, 16, 32);
1147 
1148             if (DBG) {
1149                 Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
1150                   ":" + Arrays.toString(randomizer));
1151             }
1152             return new Pair<byte[], byte[]>(hash, randomizer);
1153 
1154         } catch (RemoteException e) {Log.e(TAG, "", e);}
1155         return null;
1156     }
1157 
1158     /**
1159      * Get the profile proxy object associated with the profile.
1160      *
1161      * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
1162      * {@link BluetoothProfile#A2DP}. Clients must implements
1163      * {@link BluetoothProfile.ServiceListener} to get notified of
1164      * the connection status and to get the proxy object.
1165      *
1166      * @param context Context of the application
1167      * @param listener The service Listener for connection callbacks.
1168      * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH},
1169      *                {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}.
1170      * @return true on success, false on error
1171      */
getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)1172     public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
1173                                    int profile) {
1174         if (context == null || listener == null) return false;
1175 
1176         if (profile == BluetoothProfile.HEADSET) {
1177             BluetoothHeadset headset = new BluetoothHeadset(context, listener);
1178             return true;
1179         } else if (profile == BluetoothProfile.A2DP) {
1180             BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
1181             return true;
1182         } else if (profile == BluetoothProfile.INPUT_DEVICE) {
1183             BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
1184             return true;
1185         } else if (profile == BluetoothProfile.PAN) {
1186             BluetoothPan pan = new BluetoothPan(context, listener);
1187             return true;
1188         } else if (profile == BluetoothProfile.HEALTH) {
1189             BluetoothHealth health = new BluetoothHealth(context, listener);
1190             return true;
1191         } else {
1192             return false;
1193         }
1194     }
1195 
1196     /**
1197      * Close the connection of the profile proxy to the Service.
1198      *
1199      * <p> Clients should call this when they are no longer using
1200      * the proxy obtained from {@link #getProfileProxy}.
1201      * Profile can be one of  {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
1202      * {@link BluetoothProfile#A2DP}
1203      *
1204      * @param profile
1205      * @param proxy Profile proxy object
1206      */
closeProfileProxy(int profile, BluetoothProfile proxy)1207     public void closeProfileProxy(int profile, BluetoothProfile proxy) {
1208         if (proxy == null) return;
1209 
1210         switch (profile) {
1211             case BluetoothProfile.HEADSET:
1212                 BluetoothHeadset headset = (BluetoothHeadset)proxy;
1213                 headset.close();
1214                 break;
1215             case BluetoothProfile.A2DP:
1216                 BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
1217                 a2dp.close();
1218                 break;
1219             case BluetoothProfile.INPUT_DEVICE:
1220                 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
1221                 iDev.close();
1222                 break;
1223             case BluetoothProfile.PAN:
1224                 BluetoothPan pan = (BluetoothPan)proxy;
1225                 pan.close();
1226                 break;
1227             case BluetoothProfile.HEALTH:
1228                 BluetoothHealth health = (BluetoothHealth)proxy;
1229                 health.close();
1230                 break;
1231         }
1232     }
1233 
1234     /**
1235      * Enable the Bluetooth Adapter, but don't auto-connect devices
1236      * and don't persist state. Only for use by system applications.
1237      * @hide
1238      */
enableNoAutoConnect()1239     public boolean enableNoAutoConnect() {
1240         try {
1241             return mService.enableNoAutoConnect();
1242         } catch (RemoteException e) {Log.e(TAG, "", e);}
1243         return false;
1244     }
1245 
1246     /**
1247      * Enable control of the Bluetooth Adapter for a single application.
1248      *
1249      * <p>Some applications need to use Bluetooth for short periods of time to
1250      * transfer data but don't want all the associated implications like
1251      * automatic connection to headsets etc.
1252      *
1253      * <p> Multiple applications can call this. This is reference counted and
1254      * Bluetooth disabled only when no one else is using it. There will be no UI
1255      * shown to the user while bluetooth is being enabled. Any user action will
1256      * override this call. For example, if user wants Bluetooth on and the last
1257      * user of this API wanted to disable Bluetooth, Bluetooth will not be
1258      * turned off.
1259      *
1260      * <p> This API is only meant to be used by internal applications. Third
1261      * party applications but use {@link #enable} and {@link #disable} APIs.
1262      *
1263      * <p> If this API returns true, it means the callback will be called.
1264      * The callback will be called with the current state of Bluetooth.
1265      * If the state is not what was requested, an internal error would be the
1266      * reason. If Bluetooth is already on and if this function is called to turn
1267      * it on, the api will return true and a callback will be called.
1268      *
1269      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1270      *
1271      * @param on True for on, false for off.
1272      * @param callback The callback to notify changes to the state.
1273      * @hide
1274      */
changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback)1275     public boolean changeApplicationBluetoothState(boolean on,
1276                                                    BluetoothStateChangeCallback callback) {
1277         if (callback == null) return false;
1278 
1279         try {
1280             return mService.changeApplicationBluetoothState(on, new
1281                     StateChangeCallbackWrapper(callback), new Binder());
1282         } catch (RemoteException e) {
1283             Log.e(TAG, "changeBluetoothState", e);
1284         }
1285         return false;
1286     }
1287 
1288     /**
1289      * @hide
1290      */
1291     public interface BluetoothStateChangeCallback {
onBluetoothStateChange(boolean on)1292         public void onBluetoothStateChange(boolean on);
1293     }
1294 
1295     /**
1296      * @hide
1297      */
1298     public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
1299         private BluetoothStateChangeCallback mCallback;
1300 
StateChangeCallbackWrapper(BluetoothStateChangeCallback callback)1301         StateChangeCallbackWrapper(BluetoothStateChangeCallback
1302                 callback) {
1303             mCallback = callback;
1304         }
1305 
1306         @Override
onBluetoothStateChange(boolean on)1307         public void onBluetoothStateChange(boolean on) {
1308             mCallback.onBluetoothStateChange(on);
1309         }
1310     }
1311 
toDeviceSet(String[] addresses)1312     private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
1313         Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
1314         for (int i = 0; i < addresses.length; i++) {
1315             devices.add(getRemoteDevice(addresses[i]));
1316         }
1317         return Collections.unmodifiableSet(devices);
1318     }
1319 
1320     /**
1321      * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
1322      * <p>Alphabetic characters must be uppercase to be valid.
1323      *
1324      * @param address Bluetooth address as string
1325      * @return true if the address is valid, false otherwise
1326      */
checkBluetoothAddress(String address)1327     public static boolean checkBluetoothAddress(String address) {
1328         if (address == null || address.length() != ADDRESS_LENGTH) {
1329             return false;
1330         }
1331         for (int i = 0; i < ADDRESS_LENGTH; i++) {
1332             char c = address.charAt(i);
1333             switch (i % 3) {
1334             case 0:
1335             case 1:
1336                 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
1337                     // hex character, OK
1338                     break;
1339                 }
1340                 return false;
1341             case 2:
1342                 if (c == ':') {
1343                     break;  // OK
1344                 }
1345                 return false;
1346             }
1347         }
1348         return true;
1349     }
1350 }
1351