BluetoothAdapter.java revision de893f550301a60274e87aa8168225e7a7a42184
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.RemoteException;
22import android.util.Log;
23
24import java.io.IOException;
25import java.util.Collections;
26import java.util.Set;
27import java.util.HashSet;
28
29/**
30 * Represents the local Bluetooth adapter.
31 *
32 * <p>Use {@link android.content.Context#getSystemService} with {@link
33 * android.content.Context#BLUETOOTH_SERVICE} to get the default local
34 * Bluetooth adapter. On most Android devices there is only one local
35 * Bluetotoh adapter.
36 *
37 * <p>Use the {@link BluetoothDevice} class for operations on remote Bluetooth
38 * devices.
39 *
40 * <p>TODO: unhide more of this class
41 */
42public final class BluetoothAdapter {
43    private static final String TAG = "BluetoothAdapter";
44
45    /**
46     * Broadcast Action: The state of the local Bluetooth adapter has been
47     * changed.
48     * <p>For example, Bluetooth has been turned on or off.
49     * <p>Contains the extra fields {@link #EXTRA_STATE} and {@link
50     * #EXTRA_PREVIOUS_STATE} containing the new and old states
51     * respectively.
52     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
53     */
54    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
55    public static final String ACTION_STATE_CHANGED =
56            "android.bluetooth.intent.action.STATE_CHANGED";
57
58    /**
59     * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
60     * intents to request the current power state. Possible values are:
61     * {@link #STATE_OFF},
62     * {@link #STATE_TURNING_ON},
63     * {@link #STATE_ON},
64     * {@link #STATE_TURNING_OFF},
65     */
66    public static final String EXTRA_STATE =
67            "android.bluetooth.intent.extra.STATE";
68    /**
69     * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
70     * intents to request the previous power state. Possible values are:
71     * {@link #STATE_OFF},
72     * {@link #STATE_TURNING_ON},
73     * {@link #STATE_ON},
74     * {@link #STATE_TURNING_OFF},
75     */
76    public static final String EXTRA_PREVIOUS_STATE =
77            "android.bluetooth.intent.extra.PREVIOUS_STATE";
78
79    /**
80     * Indicates the local Bluetooth adapter is off.
81     */
82    public static final int STATE_OFF = 40;
83    /**
84     * Indicates the local Bluetooth adapter is turning on. However local
85     * clients should wait for {@link #STATE_ON} before attempting to
86     * use the adapter.
87     */
88    public static final int STATE_TURNING_ON = 41;
89    /**
90     * Indicates the local Bluetooth adapter is on, and ready for use.
91     */
92    public static final int STATE_ON = 42;
93    /**
94     * Indicates the local Bluetooth adapter is turning off. Local clients
95     * should immediately attempt graceful disconnection of any remote links.
96     */
97    public static final int STATE_TURNING_OFF = 43;
98
99    /**
100     * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
101     * has changed.
102     * <p>Contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
103     * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
104     * respectively.
105     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
106     */
107    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
108    public static final String ACTION_SCAN_MODE_CHANGED =
109            "android.bluetooth.intent.action.SCAN_MODE_CHANGED";
110
111    /**
112     * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
113     * intents to request the current scan mode. Possible values are:
114     * {@link #SCAN_MODE_NONE},
115     * {@link #SCAN_MODE_CONNECTABLE},
116     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
117     */
118    public static final String EXTRA_SCAN_MODE = "android.bluetooth.intent.extra.SCAN_MODE";
119    /**
120     * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
121     * intents to request the previous scan mode. Possible values are:
122     * {@link #SCAN_MODE_NONE},
123     * {@link #SCAN_MODE_CONNECTABLE},
124     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
125     */
126    public static final String EXTRA_PREVIOUS_SCAN_MODE =
127            "android.bluetooth.intent.extra.PREVIOUS_SCAN_MODE";
128
129    /**
130     * Indicates that both inquiry scan and page scan are disabled on the local
131     * Bluetooth adapter. Therefore this device is neither discoverable
132     * nor connectable from remote Bluetooth devices.
133     */
134    public static final int SCAN_MODE_NONE = 50;
135    /**
136     * Indicates that inquiry scan is disabled, but page scan is enabled on the
137     * local Bluetooth adapter. Therefore this device is not discoverable from
138     * remote Bluetooth devices, but is connectable from remote devices that
139     * have previously discovered this device.
140     */
141    public static final int SCAN_MODE_CONNECTABLE = 51;
142    /**
143     * Indicates that both inquiry scan and page scan are enabled on the local
144     * Bluetooth adapter. Therefore this device is both discoverable and
145     * connectable from remote Bluetooth devices.
146     */
147    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 53;
148
149    /** The user will be prompted to enter a pin
150     * @hide */
151    public static final int PAIRING_VARIANT_PIN = 0;
152    /** The user will be prompted to enter a passkey
153     * @hide */
154    public static final int PAIRING_VARIANT_PASSKEY = 1;
155    /** The user will be prompted to confirm the passkey displayed on the screen
156     * @hide */
157    public static final int PAIRING_VARIANT_CONFIRMATION = 2;
158
159    private final IBluetooth mService;
160
161    /**
162     * Do not use this constructor. Use Context.getSystemService() instead.
163     * @hide
164     */
165    public BluetoothAdapter(IBluetooth service) {
166        if (service == null) {
167            throw new IllegalArgumentException("service is null");
168        }
169        mService = service;
170    }
171
172    /**
173     * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
174     * address.
175     * <p>Valid Bluetooth hardware addresses must be upper case, in a format
176     * such as "00:11:22:33:AA:BB".
177     * <p>A {@link BluetoothDevice} will always be returned for a valid
178     * hardware address, even if this adapter has never seen that device.
179     *
180     * @param address valid Bluetooth MAC address
181     * @throws IllegalArgumentException if address is invalid
182     */
183    public BluetoothDevice getRemoteDevice(String address) {
184        return new BluetoothDevice(address);
185    }
186
187    /**
188     * Return true if Bluetooth is currently enabled and ready for use.
189     * <p>Equivalent to:
190     * <code>getBluetoothState() == STATE_ON</code>
191     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
192     *
193     * @return true if the local adapter is turned on
194     */
195    public boolean isEnabled() {
196        try {
197            return mService.isEnabled();
198        } catch (RemoteException e) {Log.e(TAG, "", e);}
199        return false;
200    }
201
202    /**
203     * Get the current state of the local Bluetooth adapter.
204     * <p>Possible return values are
205     * {@link #STATE_OFF},
206     * {@link #STATE_TURNING_ON},
207     * {@link #STATE_ON},
208     * {@link #STATE_TURNING_OFF}.
209     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
210     *
211     * @return current state of Bluetooth adapter
212     */
213    public int getState() {
214        try {
215            return mService.getBluetoothState();
216        } catch (RemoteException e) {Log.e(TAG, "", e);}
217        return STATE_OFF;
218    }
219
220    /**
221     * Turn on the local Bluetooth adapter.
222     * <p>This powers on the underlying Bluetooth hardware, and starts all
223     * Bluetooth system services.
224     * <p>This is an asynchronous call: it will return immediatley, and
225     * clients should listen for {@link #ACTION_STATE_CHANGED}
226     * to be notified of subsequent adapter state changes. If this call returns
227     * true, then the adapter state will immediately transition from {@link
228     * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
229     * later transition to either {@link #STATE_OFF} or {@link
230     * #STATE_ON}. If this call returns false then there was an
231     * immediate problem that will prevent the adapter from being turned on -
232     * such as Airplane mode, or the adapter is already turned on.
233     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
234     *
235     * @return true to indicate adapter startup has begun, or false on
236     *         immediate error
237     */
238    public boolean enable() {
239        try {
240            return mService.enable();
241        } catch (RemoteException e) {Log.e(TAG, "", e);}
242        return false;
243    }
244
245    /**
246     * Turn off the local Bluetooth adapter.
247     * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
248     * system services, and powers down the underlying Bluetooth hardware.
249     * <p>This is an asynchronous call: it will return immediatley, and
250     * clients should listen for {@link #ACTION_STATE_CHANGED}
251     * to be notified of subsequent adapter state changes. If this call returns
252     * true, then the adapter state will immediately transition from {@link
253     * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
254     * later transition to either {@link #STATE_OFF} or {@link
255     * #STATE_ON}. If this call returns false then there was an
256     * immediate problem that will prevent the adapter from being turned off -
257     * such as the adapter already being turned off.
258     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
259     *
260     * @return true to indicate adapter shutdown has begun, or false on
261     *         immediate error
262     */
263    public boolean disable() {
264        try {
265            return mService.disable(true);
266        } catch (RemoteException e) {Log.e(TAG, "", e);}
267        return false;
268    }
269
270    /**
271     * Returns the hardware address of the local Bluetooth adapter.
272     * <p>For example, "00:11:22:AA:BB:CC".
273     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
274     *
275     * @return Bluetooth hardware address as string
276     */
277    public String getAddress() {
278        try {
279            return mService.getAddress();
280        } catch (RemoteException e) {Log.e(TAG, "", e);}
281        return null;
282    }
283
284    /**
285     * Get the friendly Bluetooth name of the local Bluetooth adapter.
286     * <p>This name is visible to remote Bluetooth devices.
287     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
288     *
289     * @return the Bluetooth name, or null on error
290     */
291    public String getName() {
292        try {
293            return mService.getName();
294        } catch (RemoteException e) {Log.e(TAG, "", e);}
295        return null;
296    }
297
298    /**
299     * Set the friendly Bluetooth name of the local Bluetoth adapter.
300     * <p>This name is visible to remote Bluetooth devices.
301     * <p>Valid Bluetooth names are a maximum of 248 UTF-8 characters, however
302     * many remote devices can only display the first 40 characters, and some
303     * may be limited to just 20.
304     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
305     *
306     * @param name a valid Bluetooth name
307     * @return     true if the name was set, false otherwise
308     */
309    public boolean setName(String name) {
310        try {
311            return mService.setName(name);
312        } catch (RemoteException e) {Log.e(TAG, "", e);}
313        return false;
314    }
315
316    /**
317     * Get the current Bluetooth scan mode of the local Bluetooth adaper.
318     * <p>The Bluetooth scan mode determines if the local adapter is
319     * connectable and/or discoverable from remote Bluetooth devices.
320     * <p>Possible values are:
321     * {@link #SCAN_MODE_NONE},
322     * {@link #SCAN_MODE_CONNECTABLE},
323     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
324     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
325     *
326     * @return scan mode
327     */
328    public int getScanMode() {
329        try {
330            return mService.getScanMode();
331        } catch (RemoteException e) {Log.e(TAG, "", e);}
332        return SCAN_MODE_NONE;
333    }
334
335    /**
336     * Set the Bluetooth scan mode of the local Bluetooth adapter.
337     * <p>The Bluetooth scan mode determines if the local adapter is
338     * connectable and/or discoverable from remote Bluetooth devices.
339     * <p>For privacy reasons, it is recommended to limit the duration of time
340     * that the local adapter remains in a discoverable scan mode. For example,
341     * 2 minutes is a generous time to allow a remote Bluetooth device to
342     * initiate and complete its discovery process.
343     * <p>Valid scan mode values are:
344     * {@link #SCAN_MODE_NONE},
345     * {@link #SCAN_MODE_CONNECTABLE},
346     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
347     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
348     *
349     * @param mode valid scan mode
350     * @return     true if the scan mode was set, false otherwise
351     */
352    public boolean setScanMode(int mode) {
353        try {
354            return mService.setScanMode(mode);
355        } catch (RemoteException e) {Log.e(TAG, "", e);}
356        return false;
357    }
358
359    /** @hide */
360    public int getDiscoverableTimeout() {
361        try {
362            return mService.getDiscoverableTimeout();
363        } catch (RemoteException e) {Log.e(TAG, "", e);}
364        return -1;
365    }
366
367    /** @hide */
368    public void setDiscoverableTimeout(int timeout) {
369        try {
370            mService.setDiscoverableTimeout(timeout);
371        } catch (RemoteException e) {Log.e(TAG, "", e);}
372    }
373
374    /** @hide */
375    public boolean startDiscovery() {
376        try {
377            return mService.startDiscovery();
378        } catch (RemoteException e) {Log.e(TAG, "", e);}
379        return false;
380    }
381
382    /** @hide */
383    public void cancelDiscovery() {
384        try {
385            mService.cancelDiscovery();
386        } catch (RemoteException e) {Log.e(TAG, "", e);}
387    }
388
389    /** @hide */
390    public boolean isDiscovering() {
391        try {
392            return mService.isDiscovering();
393        } catch (RemoteException e) {Log.e(TAG, "", e);}
394        return false;
395    }
396
397    /**
398     * List remote devices that are bonded (paired) to the local adapter.
399     *
400     * Bonding (pairing) is the process by which the user enters a pin code for
401     * the device, which generates a shared link key, allowing for
402     * authentication and encryption of future connections. In Android we
403     * require bonding before RFCOMM or SCO connections can be made to a remote
404     * device.
405     *
406     * This function lists which remote devices we have a link key for. It does
407     * not cause any RF transmission, and does not check if the remote device
408     * still has it's link key with us. If the other side no longer has its
409     * link key then the RFCOMM or SCO connection attempt will result in an
410     * error.
411     *
412     * This function does not check if the remote device is in range.
413     *
414     * Remote devices that have an in-progress bonding attempt are not
415     * returned.
416     *
417     * @return unmodifiable set of bonded devices, or null on error
418     * @hide
419     */
420    public Set<BluetoothDevice> getBondedDevices() {
421        try {
422            return toDeviceSet(mService.listBonds());
423        } catch (RemoteException e) {Log.e(TAG, "", e);}
424        return null;
425    }
426
427    /**
428     * Create a listening, secure RFCOMM Bluetooth socket.
429     * <p>A remote device connecting to this socket will be authenticated and
430     * communication on this socket will be encrypted.
431     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
432     * connections to listening {@link BluetoothServerSocket}.
433     * <p>Valid RFCOMM channels are in range 1 to 30.
434     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
435     * @param channel RFCOMM channel to listen on
436     * @return a listening RFCOMM BluetoothServerSocket
437     * @throws IOException on error, for example Bluetooth not available, or
438     *                     insufficient permissions, or channel in use.
439     */
440    public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
441        BluetoothServerSocket socket = new BluetoothServerSocket(
442                BluetoothSocket.TYPE_RFCOMM, true, true, channel);
443        try {
444            socket.mSocket.bindListen();
445        } catch (IOException e) {
446            try {
447                socket.close();
448            } catch (IOException e2) { }
449            throw e;
450        }
451        return socket;
452    }
453
454    /**
455     * Construct an unencrypted, unauthenticated, RFCOMM server socket.
456     * Call #accept to retrieve connections to this socket.
457     * @return An RFCOMM BluetoothServerSocket
458     * @throws IOException On error, for example Bluetooth not available, or
459     *                     insufficient permissions.
460     * @hide
461     */
462    public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
463        BluetoothServerSocket socket = new BluetoothServerSocket(
464                BluetoothSocket.TYPE_RFCOMM, false, false, port);
465        try {
466            socket.mSocket.bindListen();
467        } catch (IOException e) {
468            try {
469                socket.close();
470            } catch (IOException e2) { }
471            throw e;
472        }
473        return socket;
474    }
475
476    /**
477     * Construct a SCO server socket.
478     * Call #accept to retrieve connections to this socket.
479     * @return A SCO BluetoothServerSocket
480     * @throws IOException On error, for example Bluetooth not available, or
481     *                     insufficient permissions.
482     * @hide
483     */
484    public static BluetoothServerSocket listenUsingScoOn() throws IOException {
485        BluetoothServerSocket socket = new BluetoothServerSocket(
486                BluetoothSocket.TYPE_SCO, false, false, -1);
487        try {
488            socket.mSocket.bindListen();
489        } catch (IOException e) {
490            try {
491                socket.close();
492            } catch (IOException e2) { }
493            throw e;
494        }
495        return socket;
496    }
497
498    private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
499        Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
500        for (int i = 0; i < addresses.length; i++) {
501            devices.add(getRemoteDevice(addresses[i]));
502        }
503        return Collections.unmodifiableSet(devices);
504    }
505}
506