BluetoothAdapter.java revision a3363ef2cdf27e8d652297e9b916d085c5550a28
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
17package android.bluetooth;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.os.Binder;
22import android.os.Handler;
23import android.os.IBinder;
24import android.os.Message;
25import android.os.ParcelUuid;
26import android.os.RemoteException;
27import android.os.ServiceManager;
28import android.util.Log;
29import android.util.Pair;
30
31import java.io.IOException;
32import java.util.Arrays;
33import java.util.Collections;
34import java.util.HashSet;
35import java.util.LinkedList;
36import java.util.Random;
37import java.util.Set;
38import java.util.UUID;
39
40/**
41 * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
42 * lets you perform fundamental Bluetooth tasks, such as initiate
43 * device discovery, query a list of bonded (paired) devices,
44 * instantiate a {@link BluetoothDevice} using a known MAC address, and create
45 * a {@link BluetoothServerSocket} to listen for connection requests from other
46 * devices.
47 *
48 * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
49 * adapter, call the static {@link #getDefaultAdapter} method.
50 * Fundamentally, this is your starting point for all
51 * Bluetooth actions. Once you have the local adapter, you can get a set of
52 * {@link BluetoothDevice} objects representing all paired devices with
53 * {@link #getBondedDevices()}; start device discovery with
54 * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
55 * listen for incoming connection requests with
56 * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}.
57 *
58 * <p class="note"><strong>Note:</strong>
59 * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
60 * permission and some also require the
61 * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
62 *
63 * {@see BluetoothDevice}
64 * {@see BluetoothServerSocket}
65 */
66public final class BluetoothAdapter {
67    private static final String TAG = "BluetoothAdapter";
68    private static final boolean DBG = false;
69
70    /**
71     * Sentinel error value for this class. Guaranteed to not equal any other
72     * integer constant in this class. Provided as a convenience for functions
73     * that require a sentinel error value, for example:
74     * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
75     * BluetoothAdapter.ERROR)</code>
76     */
77    public static final int ERROR = Integer.MIN_VALUE;
78
79    /**
80     * Broadcast Action: The state of the local Bluetooth adapter has been
81     * changed.
82     * <p>For example, Bluetooth has been turned on or off.
83     * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
84     * #EXTRA_PREVIOUS_STATE} containing the new and old states
85     * respectively.
86     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
87     */
88    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
89    public static final String ACTION_STATE_CHANGED =
90            "android.bluetooth.adapter.action.STATE_CHANGED";
91
92    /**
93     * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
94     * intents to request the current power state. Possible values are:
95     * {@link #STATE_OFF},
96     * {@link #STATE_TURNING_ON},
97     * {@link #STATE_ON},
98     * {@link #STATE_TURNING_OFF},
99     */
100    public static final String EXTRA_STATE =
101            "android.bluetooth.adapter.extra.STATE";
102    /**
103     * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
104     * intents to request the previous 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_PREVIOUS_STATE =
111            "android.bluetooth.adapter.extra.PREVIOUS_STATE";
112
113    /**
114     * Indicates the local Bluetooth adapter is off.
115     */
116    public static final int STATE_OFF = 10;
117    /**
118     * Indicates the local Bluetooth adapter is turning on. However local
119     * clients should wait for {@link #STATE_ON} before attempting to
120     * use the adapter.
121     */
122    public static final int STATE_TURNING_ON = 11;
123    /**
124     * Indicates the local Bluetooth adapter is on, and ready for use.
125     */
126    public static final int STATE_ON = 12;
127    /**
128     * Indicates the local Bluetooth adapter is turning off. Local clients
129     * should immediately attempt graceful disconnection of any remote links.
130     */
131    public static final int STATE_TURNING_OFF = 13;
132
133    /**
134     * Activity Action: Show a system activity that requests discoverable mode.
135     * This activity will also request the user to turn on Bluetooth if it
136     * is not currently enabled.
137     * <p>Discoverable mode is equivalent to {@link
138     * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see
139     * this Bluetooth adapter when they perform a discovery.
140     * <p>For privacy, Android is not discoverable by default.
141     * <p>The sender of this Intent can optionally use extra field {@link
142     * #EXTRA_DISCOVERABLE_DURATION} to request the duration of
143     * discoverability. Currently the default duration is 120 seconds, and
144     * maximum duration is capped at 300 seconds for each request.
145     * <p>Notification of the result of this activity is posted using the
146     * {@link android.app.Activity#onActivityResult} callback. The
147     * <code>resultCode</code>
148     * will be the duration (in seconds) of discoverability or
149     * {@link android.app.Activity#RESULT_CANCELED} if the user rejected
150     * discoverability or an error has occurred.
151     * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
152     * for global notification whenever the scan mode changes. For example, an
153     * application can be notified when the device has ended discoverability.
154     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
155     */
156    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
157    public static final String ACTION_REQUEST_DISCOVERABLE =
158            "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
159
160    /**
161     * Used as an optional int extra field in {@link
162     * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration
163     * for discoverability in seconds. The current default is 120 seconds, and
164     * requests over 300 seconds will be capped. These values could change.
165     */
166    public static final String EXTRA_DISCOVERABLE_DURATION =
167            "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
168
169    /**
170     * Activity Action: Show a system activity that allows the user to turn on
171     * Bluetooth.
172     * <p>This system activity will return once Bluetooth has completed turning
173     * on, or the user has decided not to turn Bluetooth on.
174     * <p>Notification of the result of this activity is posted using the
175     * {@link android.app.Activity#onActivityResult} callback. The
176     * <code>resultCode</code>
177     * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
178     * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
179     * has rejected the request or an error has occurred.
180     * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
181     * for global notification whenever Bluetooth is turned on or off.
182     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
183     */
184    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
185    public static final String ACTION_REQUEST_ENABLE =
186            "android.bluetooth.adapter.action.REQUEST_ENABLE";
187
188    /**
189     * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
190     * has changed.
191     * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
192     * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
193     * respectively.
194     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
195     */
196    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
197    public static final String ACTION_SCAN_MODE_CHANGED =
198            "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
199
200    /**
201     * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
202     * intents to request the current scan mode. Possible values are:
203     * {@link #SCAN_MODE_NONE},
204     * {@link #SCAN_MODE_CONNECTABLE},
205     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
206     */
207    public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
208    /**
209     * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
210     * intents to request the previous 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_PREVIOUS_SCAN_MODE =
216            "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
217
218    /**
219     * Indicates that both inquiry scan and page scan are disabled on the local
220     * Bluetooth adapter. Therefore this device is neither discoverable
221     * nor connectable from remote Bluetooth devices.
222     */
223    public static final int SCAN_MODE_NONE = 20;
224    /**
225     * Indicates that inquiry scan is disabled, but page scan is enabled on the
226     * local Bluetooth adapter. Therefore this device is not discoverable from
227     * remote Bluetooth devices, but is connectable from remote devices that
228     * have previously discovered this device.
229     */
230    public static final int SCAN_MODE_CONNECTABLE = 21;
231    /**
232     * Indicates that both inquiry scan and page scan are enabled on the local
233     * Bluetooth adapter. Therefore this device is both discoverable and
234     * connectable from remote Bluetooth devices.
235     */
236    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
237
238
239    /**
240     * Broadcast Action: The local Bluetooth adapter has started the remote
241     * device discovery process.
242     * <p>This usually involves an inquiry scan of about 12 seconds, followed
243     * by a page scan of each new device to retrieve its Bluetooth name.
244     * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
245     * remote Bluetooth devices are found.
246     * <p>Device discovery is a heavyweight procedure. New connections to
247     * remote Bluetooth devices should not be attempted while discovery is in
248     * progress, and existing connections will experience limited bandwidth
249     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
250     * discovery.
251     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
252     */
253    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
254    public static final String ACTION_DISCOVERY_STARTED =
255            "android.bluetooth.adapter.action.DISCOVERY_STARTED";
256    /**
257     * Broadcast Action: The local Bluetooth adapter has finished the device
258     * discovery process.
259     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
260     */
261    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
262    public static final String ACTION_DISCOVERY_FINISHED =
263            "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
264
265    /**
266     * Broadcast Action: The local Bluetooth adapter has changed its friendly
267     * Bluetooth name.
268     * <p>This name is visible to remote Bluetooth devices.
269     * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
270     * the name.
271     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
272     */
273    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
274    public static final String ACTION_LOCAL_NAME_CHANGED =
275            "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
276    /**
277     * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
278     * intents to request the local Bluetooth name.
279     */
280    public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
281
282    /** @hide */
283    public static final String BLUETOOTH_SERVICE = "bluetooth";
284
285    private static final int ADDRESS_LENGTH = 17;
286
287    /**
288     * Lazily initialized singleton. Guaranteed final after first object
289     * constructed.
290     */
291    private static BluetoothAdapter sAdapter;
292
293    private final IBluetooth mService;
294
295    /**
296     * Get a handle to the default local Bluetooth adapter.
297     * <p>Currently Android only supports one Bluetooth adapter, but the API
298     * could be extended to support more. This will always return the default
299     * adapter.
300     * @return the default local adapter, or null if Bluetooth is not supported
301     *         on this hardware platform
302     */
303    public static synchronized BluetoothAdapter getDefaultAdapter() {
304        if (sAdapter == null) {
305            IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
306            if (b != null) {
307                IBluetooth service = IBluetooth.Stub.asInterface(b);
308                sAdapter = new BluetoothAdapter(service);
309            }
310        }
311        return sAdapter;
312    }
313
314    /**
315     * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
316     * @hide
317     */
318    public BluetoothAdapter(IBluetooth service) {
319        if (service == null) {
320            throw new IllegalArgumentException("service is null");
321        }
322        mService = service;
323    }
324
325    /**
326     * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
327     * address.
328     * <p>Valid Bluetooth hardware addresses must be upper case, in a format
329     * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
330     * available to validate a Bluetooth address.
331     * <p>A {@link BluetoothDevice} will always be returned for a valid
332     * hardware address, even if this adapter has never seen that device.
333     *
334     * @param address valid Bluetooth MAC address
335     * @throws IllegalArgumentException if address is invalid
336     */
337    public BluetoothDevice getRemoteDevice(String address) {
338        return new BluetoothDevice(address);
339    }
340
341    /**
342     * Return true if Bluetooth is currently enabled and ready for use.
343     * <p>Equivalent to:
344     * <code>getBluetoothState() == STATE_ON</code>
345     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
346     *
347     * @return true if the local adapter is turned on
348     */
349    public boolean isEnabled() {
350        try {
351            return mService.isEnabled();
352        } catch (RemoteException e) {Log.e(TAG, "", e);}
353        return false;
354    }
355
356    /**
357     * Get the current state of the local Bluetooth adapter.
358     * <p>Possible return values are
359     * {@link #STATE_OFF},
360     * {@link #STATE_TURNING_ON},
361     * {@link #STATE_ON},
362     * {@link #STATE_TURNING_OFF}.
363     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
364     *
365     * @return current state of Bluetooth adapter
366     */
367    public int getState() {
368        try {
369            return mService.getBluetoothState();
370        } catch (RemoteException e) {Log.e(TAG, "", e);}
371        return STATE_OFF;
372    }
373
374    /**
375     * Turn on the local Bluetooth adapter&mdash;do not use without explicit
376     * user action to turn on Bluetooth.
377     * <p>This powers on the underlying Bluetooth hardware, and starts all
378     * Bluetooth system services.
379     * <p class="caution"><strong>Bluetooth should never be enabled without
380     * direct user consent</strong>. If you want to turn on Bluetooth in order
381     * to create a wireless connection, you should use the {@link
382     * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
383     * user permission to turn on Bluetooth. The {@link #enable()} method is
384     * provided only for applications that include a user interface for changing
385     * system settings, such as a "power manager" app.</p>
386     * <p>This is an asynchronous call: it will return immediately, and
387     * clients should listen for {@link #ACTION_STATE_CHANGED}
388     * to be notified of subsequent adapter state changes. If this call returns
389     * true, then the adapter state will immediately transition from {@link
390     * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
391     * later transition to either {@link #STATE_OFF} or {@link
392     * #STATE_ON}. If this call returns false then there was an
393     * immediate problem that will prevent the adapter from being turned on -
394     * such as Airplane mode, or the adapter is already turned on.
395     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
396     * permission
397     *
398     * @return true to indicate adapter startup has begun, or false on
399     *         immediate error
400     */
401    public boolean enable() {
402        try {
403            return mService.enable();
404        } catch (RemoteException e) {Log.e(TAG, "", e);}
405        return false;
406    }
407
408    /**
409     * Turn off the local Bluetooth adapter&mdash;do not use without explicit
410     * user action to turn off Bluetooth.
411     * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
412     * system services, and powers down the underlying Bluetooth hardware.
413     * <p class="caution"><strong>Bluetooth should never be disabled without
414     * direct user consent</strong>. The {@link #disable()} method is
415     * provided only for applications that include a user interface for changing
416     * system settings, such as a "power manager" app.</p>
417     * <p>This is an asynchronous call: it will return immediately, and
418     * clients should listen for {@link #ACTION_STATE_CHANGED}
419     * to be notified of subsequent adapter state changes. If this call returns
420     * true, then the adapter state will immediately transition from {@link
421     * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
422     * later transition to either {@link #STATE_OFF} or {@link
423     * #STATE_ON}. If this call returns false then there was an
424     * immediate problem that will prevent the adapter from being turned off -
425     * such as the adapter already being turned off.
426     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
427     * permission
428     *
429     * @return true to indicate adapter shutdown has begun, or false on
430     *         immediate error
431     */
432    public boolean disable() {
433        try {
434            return mService.disable(true);
435        } catch (RemoteException e) {Log.e(TAG, "", e);}
436        return false;
437    }
438
439    /**
440     * Returns the hardware address of the local Bluetooth adapter.
441     * <p>For example, "00:11:22:AA:BB:CC".
442     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
443     *
444     * @return Bluetooth hardware address as string
445     */
446    public String getAddress() {
447        try {
448            return mService.getAddress();
449        } catch (RemoteException e) {Log.e(TAG, "", e);}
450        return null;
451    }
452
453    /**
454     * Get the friendly Bluetooth name of the local Bluetooth adapter.
455     * <p>This name is visible to remote Bluetooth devices.
456     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
457     *
458     * @return the Bluetooth name, or null on error
459     */
460    public String getName() {
461        try {
462            return mService.getName();
463        } catch (RemoteException e) {Log.e(TAG, "", e);}
464        return null;
465    }
466
467    /**
468     * Set the friendly Bluetooth name of the local Bluetooth adapter.
469     * <p>This name is visible to remote Bluetooth devices.
470     * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
471     * encoding, although many remote devices can only display the first
472     * 40 characters, and some may be limited to just 20.
473     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
474     * will return false. After turning on Bluetooth,
475     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
476     * to get the updated value.
477     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
478     *
479     * @param name a valid Bluetooth name
480     * @return     true if the name was set, false otherwise
481     */
482    public boolean setName(String name) {
483        if (getState() != STATE_ON) return false;
484        try {
485            return mService.setName(name);
486        } catch (RemoteException e) {Log.e(TAG, "", e);}
487        return false;
488    }
489
490    /**
491     * Get the current Bluetooth scan mode of the local Bluetooth adapter.
492     * <p>The Bluetooth scan mode determines if the local adapter is
493     * connectable and/or discoverable from remote Bluetooth devices.
494     * <p>Possible values are:
495     * {@link #SCAN_MODE_NONE},
496     * {@link #SCAN_MODE_CONNECTABLE},
497     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
498     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
499     * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
500     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
501     * to get the updated value.
502     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
503     *
504     * @return scan mode
505     */
506    public int getScanMode() {
507        if (getState() != STATE_ON) return SCAN_MODE_NONE;
508        try {
509            return mService.getScanMode();
510        } catch (RemoteException e) {Log.e(TAG, "", e);}
511        return SCAN_MODE_NONE;
512    }
513
514    /**
515     * Set the Bluetooth scan mode of the local Bluetooth adapter.
516     * <p>The Bluetooth scan mode determines if the local adapter is
517     * connectable and/or discoverable from remote Bluetooth devices.
518     * <p>For privacy reasons, discoverable mode is automatically turned off
519     * after <code>duration</code> seconds. For example, 120 seconds should be
520     * enough for a remote device to initiate and complete its discovery
521     * process.
522     * <p>Valid scan mode values are:
523     * {@link #SCAN_MODE_NONE},
524     * {@link #SCAN_MODE_CONNECTABLE},
525     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
526     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
527     * will return false. After turning on Bluetooth,
528     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
529     * to get the updated value.
530     * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
531     * <p>Applications cannot set the scan mode. They should use
532     * <code>startActivityForResult(
533     * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
534     * </code>instead.
535     *
536     * @param mode valid scan mode
537     * @param duration time in seconds to apply scan mode, only used for
538     *                 {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
539     * @return     true if the scan mode was set, false otherwise
540     * @hide
541     */
542    public boolean setScanMode(int mode, int duration) {
543        if (getState() != STATE_ON) return false;
544        try {
545            return mService.setScanMode(mode, duration);
546        } catch (RemoteException e) {Log.e(TAG, "", e);}
547        return false;
548    }
549
550    /** @hide */
551    public boolean setScanMode(int mode) {
552        if (getState() != STATE_ON) return false;
553        return setScanMode(mode, 120);
554    }
555
556    /** @hide */
557    public int getDiscoverableTimeout() {
558        if (getState() != STATE_ON) return -1;
559        try {
560            return mService.getDiscoverableTimeout();
561        } catch (RemoteException e) {Log.e(TAG, "", e);}
562        return -1;
563    }
564
565    /** @hide */
566    public void setDiscoverableTimeout(int timeout) {
567        if (getState() != STATE_ON) return;
568        try {
569            mService.setDiscoverableTimeout(timeout);
570        } catch (RemoteException e) {Log.e(TAG, "", e);}
571    }
572
573    /**
574     * Start the remote device discovery process.
575     * <p>The discovery process usually involves an inquiry scan of about 12
576     * seconds, followed by a page scan of each new device to retrieve its
577     * Bluetooth name.
578     * <p>This is an asynchronous call, it will return immediately. Register
579     * for {@link #ACTION_DISCOVERY_STARTED} and {@link
580     * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
581     * discovery starts and completes. Register for {@link
582     * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
583     * are found.
584     * <p>Device discovery is a heavyweight procedure. New connections to
585     * remote Bluetooth devices should not be attempted while discovery is in
586     * progress, and existing connections will experience limited bandwidth
587     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
588     * discovery. Discovery is not managed by the Activity,
589     * but is run as a system service, so an application should always call
590     * {@link BluetoothAdapter#cancelDiscovery()} even if it
591     * did not directly request a discovery, just to be sure.
592     * <p>Device discovery will only find remote devices that are currently
593     * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
594     * not discoverable by default, and need to be entered into a special mode.
595     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
596     * will return false. After turning on Bluetooth,
597     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
598     * to get the updated value.
599     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
600     *
601     * @return true on success, false on error
602     */
603    public boolean startDiscovery() {
604        if (getState() != STATE_ON) return false;
605        try {
606            return mService.startDiscovery();
607        } catch (RemoteException e) {Log.e(TAG, "", e);}
608        return false;
609    }
610
611    /**
612     * Cancel the current device discovery process.
613     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
614     * <p>Because discovery is a heavyweight procedure for the Bluetooth
615     * adapter, this method should always be called before attempting to connect
616     * to a remote device with {@link
617     * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
618     * the  Activity, but is run as a system service, so an application should
619     * always call cancel discovery even if it did not directly request a
620     * discovery, just to be sure.
621     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
622     * will return false. After turning on Bluetooth,
623     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
624     * to get the updated value.
625     *
626     * @return true on success, false on error
627     */
628    public boolean cancelDiscovery() {
629        if (getState() != STATE_ON) return false;
630        try {
631            mService.cancelDiscovery();
632        } catch (RemoteException e) {Log.e(TAG, "", e);}
633        return false;
634    }
635
636    /**
637     * Return true if the local Bluetooth adapter is currently in the device
638     * discovery process.
639     * <p>Device discovery is a heavyweight procedure. New connections to
640     * remote Bluetooth devices should not be attempted while discovery is in
641     * progress, and existing connections will experience limited bandwidth
642     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
643     * discovery.
644     * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
645     * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
646     * starts or completes.
647     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
648     * will return false. After turning on Bluetooth,
649     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
650     * to get the updated value.
651     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
652     *
653     * @return true if discovering
654     */
655    public boolean isDiscovering() {
656        if (getState() != STATE_ON) return false;
657        try {
658            return mService.isDiscovering();
659        } catch (RemoteException e) {Log.e(TAG, "", e);}
660        return false;
661    }
662
663    /**
664     * Return the set of {@link BluetoothDevice} objects that are bonded
665     * (paired) to the local adapter.
666     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
667     * will return an empty set. After turning on Bluetooth,
668     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
669     * to get the updated value.
670     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
671     *
672     * @return unmodifiable set of {@link BluetoothDevice}, or null on error
673     */
674    public Set<BluetoothDevice> getBondedDevices() {
675        if (getState() != STATE_ON) {
676            return toDeviceSet(new String[0]);
677        }
678        try {
679            return toDeviceSet(mService.listBonds());
680        } catch (RemoteException e) {Log.e(TAG, "", e);}
681        return null;
682    }
683
684    /**
685     * Picks RFCOMM channels until none are left.
686     * Avoids reserved channels.
687     */
688    private static class RfcommChannelPicker {
689        private static final int[] RESERVED_RFCOMM_CHANNELS =  new int[] {
690            10,  // HFAG
691            11,  // HSAG
692            12,  // OPUSH
693            19,  // PBAP
694        };
695        private static LinkedList<Integer> sChannels;  // master list of non-reserved channels
696        private static Random sRandom;
697
698        private final LinkedList<Integer> mChannels;  // local list of channels left to try
699
700        private final UUID mUuid;
701
702        public RfcommChannelPicker(UUID uuid) {
703            synchronized (RfcommChannelPicker.class) {
704                if (sChannels == null) {
705                    // lazy initialization of non-reserved rfcomm channels
706                    sChannels = new LinkedList<Integer>();
707                    for (int i = 1; i <= BluetoothSocket.MAX_RFCOMM_CHANNEL; i++) {
708                        sChannels.addLast(new Integer(i));
709                    }
710                    for (int reserved : RESERVED_RFCOMM_CHANNELS) {
711                        sChannels.remove(new Integer(reserved));
712                    }
713                    sRandom = new Random();
714                }
715                mChannels = (LinkedList<Integer>)sChannels.clone();
716            }
717            mUuid = uuid;
718        }
719        /* Returns next random channel, or -1 if we're out */
720        public int nextChannel() {
721            if (mChannels.size() == 0) {
722                return -1;
723            }
724            return mChannels.remove(sRandom.nextInt(mChannels.size()));
725        }
726    }
727
728    /**
729     * Create a listening, secure RFCOMM Bluetooth socket.
730     * <p>A remote device connecting to this socket will be authenticated and
731     * communication on this socket will be encrypted.
732     * <p> Use this socket only if an authenticated socket link is possible.
733     * Authentication refers to the authentication of the link key to
734     * prevent man-in-the-middle type of attacks.
735     * For example, for Bluetooth 2.1 devices, if any of the devices does not
736     * have an input and output capability or just has the ability to
737     * display a numeric key, a secure socket connection is not possible.
738     * In such a case, use {#link listenUsingInsecureRfcommOn}.
739     * For more details, refer to the Security Model section 5.2 (vol 3) of
740     * Bluetooth Core Specification version 2.1 + EDR.
741     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
742     * connections from a listening {@link BluetoothServerSocket}.
743     * <p>Valid RFCOMM channels are in range 1 to 30.
744     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
745     * @param channel RFCOMM channel to listen on
746     * @return a listening RFCOMM BluetoothServerSocket
747     * @throws IOException on error, for example Bluetooth not available, or
748     *                     insufficient permissions, or channel in use.
749     * @hide
750     */
751    public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
752        BluetoothServerSocket socket = new BluetoothServerSocket(
753                BluetoothSocket.TYPE_RFCOMM, true, true, channel);
754        int errno = socket.mSocket.bindListen();
755        if (errno != 0) {
756            try {
757                socket.close();
758            } catch (IOException e) {}
759            socket.mSocket.throwErrnoNative(errno);
760        }
761        return socket;
762    }
763
764    /**
765     * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
766     * <p>A remote device connecting to this socket will be authenticated and
767     * communication on this socket will be encrypted.
768     * <p> Use this socket only if an authenticated socket link is possible.
769     * Authentication refers to the authentication of the link key to
770     * prevent man-in-the-middle type of attacks.
771     * For example, for Bluetooth 2.1 devices, if any of the devices does not
772     * have an input and output capability or just has the ability to
773     * display a numeric key, a secure socket connection is not possible.
774     * In such a case, use {#link listenUsingInsecureRfcommWithServiceRecord}.
775     * For more details, refer to the Security Model section 5.2 (vol 3) of
776     * Bluetooth Core Specification version 2.1 + EDR.
777     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
778     * connections from a listening {@link BluetoothServerSocket}.
779     * <p>The system will assign an unused RFCOMM channel to listen on.
780     * <p>The system will also register a Service Discovery
781     * Protocol (SDP) record with the local SDP server containing the specified
782     * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
783     * can use the same UUID to query our SDP server and discover which channel
784     * to connect to. This SDP record will be removed when this socket is
785     * closed, or if this application closes unexpectedly.
786     * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
787     * connect to this socket from another device using the same {@link UUID}.
788     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
789     * @param name service name for SDP record
790     * @param uuid uuid for SDP record
791     * @return a listening RFCOMM BluetoothServerSocket
792     * @throws IOException on error, for example Bluetooth not available, or
793     *                     insufficient permissions, or channel in use.
794     */
795    public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
796            throws IOException {
797        return createNewRfcommSocketAndRecord(name, uuid, true, true);
798    }
799
800    /**
801     * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
802     * <p>The link key will be unauthenticated i.e the communication is
803     * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
804     * the link key will be encrypted, as encryption is mandartory.
805     * For legacy devices (pre Bluetooth 2.1 devices) the link key will not
806     * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
807     * encrypted and authenticated communication channel is desired.
808     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
809     * connections from a listening {@link BluetoothServerSocket}.
810     * <p>The system will assign an unused RFCOMM channel to listen on.
811     * <p>The system will also register a Service Discovery
812     * Protocol (SDP) record with the local SDP server containing the specified
813     * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
814     * can use the same UUID to query our SDP server and discover which channel
815     * to connect to. This SDP record will be removed when this socket is
816     * closed, or if this application closes unexpectedly.
817     * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
818     * connect to this socket from another device using the same {@link UUID}.
819     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
820     * @param name service name for SDP record
821     * @param uuid uuid for SDP record
822     * @return a listening RFCOMM BluetoothServerSocket
823     * @throws IOException on error, for example Bluetooth not available, or
824     *                     insufficient permissions, or channel in use.
825     */
826    public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
827            throws IOException {
828        return createNewRfcommSocketAndRecord(name, uuid, false, false);
829    }
830
831    private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
832            boolean auth, boolean encrypt) throws IOException {
833        RfcommChannelPicker picker = new RfcommChannelPicker(uuid);
834
835        BluetoothServerSocket socket;
836        int channel;
837        int errno;
838        while (true) {
839            channel = picker.nextChannel();
840
841            if (channel == -1) {
842                throw new IOException("No available channels");
843            }
844
845            socket = new BluetoothServerSocket(
846                    BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel);
847            errno = socket.mSocket.bindListen();
848            if (errno == 0) {
849                if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel);
850                break;  // success
851            } else if (errno == BluetoothSocket.EADDRINUSE) {
852                if (DBG) Log.d(TAG, "RFCOMM channel " + channel + " in use");
853                try {
854                    socket.close();
855                } catch (IOException e) {}
856                continue;  // try another channel
857            } else {
858                try {
859                    socket.close();
860                } catch (IOException e) {}
861                socket.mSocket.throwErrnoNative(errno);  // Exception as a result of bindListen()
862            }
863        }
864
865        int handle = -1;
866        try {
867            handle = mService.addRfcommServiceRecord(name, new ParcelUuid(uuid), channel,
868                    new Binder());
869        } catch (RemoteException e) {Log.e(TAG, "", e);}
870        if (handle == -1) {
871            try {
872                socket.close();
873            } catch (IOException e) {}
874            throw new IOException("Not able to register SDP record for " + name);
875        }
876        socket.setCloseHandler(mHandler, handle);
877        return socket;
878    }
879
880    /**
881     * Construct an unencrypted, unauthenticated, RFCOMM server socket.
882     * Call #accept to retrieve connections to this socket.
883     * @return An RFCOMM BluetoothServerSocket
884     * @throws IOException On error, for example Bluetooth not available, or
885     *                     insufficient permissions.
886     * @hide
887     */
888    public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
889        BluetoothServerSocket socket = new BluetoothServerSocket(
890                BluetoothSocket.TYPE_RFCOMM, false, false, port);
891        int errno = socket.mSocket.bindListen();
892        if (errno != 0) {
893            try {
894                socket.close();
895            } catch (IOException e) {}
896            socket.mSocket.throwErrnoNative(errno);
897        }
898        return socket;
899    }
900
901    /**
902     * Construct a SCO server socket.
903     * Call #accept to retrieve connections to this socket.
904     * @return A SCO BluetoothServerSocket
905     * @throws IOException On error, for example Bluetooth not available, or
906     *                     insufficient permissions.
907     * @hide
908     */
909    public static BluetoothServerSocket listenUsingScoOn() throws IOException {
910        BluetoothServerSocket socket = new BluetoothServerSocket(
911                BluetoothSocket.TYPE_SCO, false, false, -1);
912        int errno = socket.mSocket.bindListen();
913        if (errno != 0) {
914            try {
915                socket.close();
916            } catch (IOException e) {}
917            socket.mSocket.throwErrnoNative(errno);
918        }
919        return socket;
920    }
921
922    /**
923     * Read the local Out of Band Pairing Data
924     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
925     *
926     * @return Pair<byte[], byte[]> of Hash and Randomizer
927     *
928     * @hide
929     */
930    public Pair<byte[], byte[]> readOutOfBandData() {
931        if (getState() != STATE_ON) return null;
932        try {
933            byte[] hash;
934            byte[] randomizer;
935
936            byte[] ret = mService.readOutOfBandData();
937
938            if (ret  == null || ret.length != 32) return null;
939
940            hash = Arrays.copyOfRange(ret, 0, 16);
941            randomizer = Arrays.copyOfRange(ret, 16, 32);
942
943            if (DBG) {
944                Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
945                  ":" + Arrays.toString(randomizer));
946            }
947            return new Pair<byte[], byte[]>(hash, randomizer);
948
949        } catch (RemoteException e) {Log.e(TAG, "", e);}
950        return null;
951    }
952
953    private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
954        Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
955        for (int i = 0; i < addresses.length; i++) {
956            devices.add(getRemoteDevice(addresses[i]));
957        }
958        return Collections.unmodifiableSet(devices);
959    }
960
961    private Handler mHandler = new Handler() {
962        public void handleMessage(Message msg) {
963            /* handle socket closing */
964            int handle = msg.what;
965            try {
966                if (DBG) Log.d(TAG, "Removing service record " + Integer.toHexString(handle));
967                mService.removeServiceRecord(handle);
968            } catch (RemoteException e) {Log.e(TAG, "", e);}
969        }
970    };
971
972    /**
973     * Validate a Bluetooth address, such as "00:43:A8:23:10:F0"
974     * <p>Alphabetic characters must be uppercase to be valid.
975     *
976     * @param address Bluetooth address as string
977     * @return true if the address is valid, false otherwise
978     */
979    public static boolean checkBluetoothAddress(String address) {
980        if (address == null || address.length() != ADDRESS_LENGTH) {
981            return false;
982        }
983        for (int i = 0; i < ADDRESS_LENGTH; i++) {
984            char c = address.charAt(i);
985            switch (i % 3) {
986            case 0:
987            case 1:
988                if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
989                    // hex character, OK
990                    break;
991                }
992                return false;
993            case 2:
994                if (c == ':') {
995                    break;  // OK
996                }
997                return false;
998            }
999        }
1000        return true;
1001    }
1002}
1003