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