blob: e420bfd8c1bfb975434832f7eb8ab891b0af6a99 [file] [log] [blame]
Nick Pellybd022f42009-08-14 18:33:38 -07001/*
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
Nick Pellyde893f52009-09-08 13:15:33 -070019import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070021import android.content.Context;
Nick Pelly24bb9b82009-10-02 20:34:18 -070022import android.os.Binder;
23import android.os.Handler;
Nick Pellyf242b7b2009-10-08 00:12:45 +020024import android.os.IBinder;
Matthew Xie484867a2011-08-25 16:45:58 -070025import android.os.Looper;
Nick Pelly24bb9b82009-10-02 20:34:18 -070026import android.os.Message;
Nick Pellyaef439e2009-09-28 12:33:17 -070027import android.os.ParcelUuid;
Nick Pellybd022f42009-08-14 18:33:38 -070028import android.os.RemoteException;
Nick Pellyf242b7b2009-10-08 00:12:45 +020029import android.os.ServiceManager;
Nick Pellybd022f42009-08-14 18:33:38 -070030import android.util.Log;
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -070031import android.util.Pair;
Nick Pellybd022f42009-08-14 18:33:38 -070032
33import java.io.IOException;
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -070034import java.util.Arrays;
Nick Pellybd022f42009-08-14 18:33:38 -070035import java.util.Collections;
Nick Pellybd022f42009-08-14 18:33:38 -070036import java.util.HashSet;
Nick Pelly24bb9b82009-10-02 20:34:18 -070037import java.util.LinkedList;
38import java.util.Random;
39import java.util.Set;
Nick Pelly16fb88a2009-10-07 07:44:03 +020040import java.util.UUID;
Nick Pellybd022f42009-08-14 18:33:38 -070041
42/**
Scott Main9fab0ae2009-11-03 18:17:59 -080043 * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
44 * lets you perform fundamental Bluetooth tasks, such as initiate
45 * device discovery, query a list of bonded (paired) devices,
46 * instantiate a {@link BluetoothDevice} using a known MAC address, and create
47 * a {@link BluetoothServerSocket} to listen for connection requests from other
Nick Pelly45e27042009-08-19 11:00:00 -070048 * devices.
Scott Main9fab0ae2009-11-03 18:17:59 -080049 *
50 * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
51 * adapter, call the static {@link #getDefaultAdapter} method.
52 * Fundamentally, this is your starting point for all
53 * Bluetooth actions. Once you have the local adapter, you can get a set of
54 * {@link BluetoothDevice} objects representing all paired devices with
55 * {@link #getBondedDevices()}; start device discovery with
56 * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
57 * listen for incoming connection requests with
58 * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}.
59 *
60 * <p class="note"><strong>Note:</strong>
61 * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
62 * permission and some also require the
63 * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
64 *
65 * {@see BluetoothDevice}
66 * {@see BluetoothServerSocket}
Nick Pellybd022f42009-08-14 18:33:38 -070067 */
68public final class BluetoothAdapter {
69 private static final String TAG = "BluetoothAdapter";
Jaikumar Ganeshaf21fa62010-05-18 14:36:48 -070070 private static final boolean DBG = false;
Nick Pellybd022f42009-08-14 18:33:38 -070071
Nick Pellyde893f52009-09-08 13:15:33 -070072 /**
Nick Pellyb24e11b2009-09-08 17:40:43 -070073 * Sentinel error value for this class. Guaranteed to not equal any other
74 * integer constant in this class. Provided as a convenience for functions
75 * that require a sentinel error value, for example:
76 * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
77 * BluetoothAdapter.ERROR)</code>
78 */
Nick Pelly005b2282009-09-10 10:21:56 -070079 public static final int ERROR = Integer.MIN_VALUE;
Nick Pellyb24e11b2009-09-08 17:40:43 -070080
81 /**
Nick Pellyde893f52009-09-08 13:15:33 -070082 * Broadcast Action: The state of the local Bluetooth adapter has been
83 * changed.
84 * <p>For example, Bluetooth has been turned on or off.
Nick Pelly005b2282009-09-10 10:21:56 -070085 * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
Nick Pellyde893f52009-09-08 13:15:33 -070086 * #EXTRA_PREVIOUS_STATE} containing the new and old states
87 * respectively.
88 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
89 */
90 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
91 public static final String ACTION_STATE_CHANGED =
Nick Pelly005b2282009-09-10 10:21:56 -070092 "android.bluetooth.adapter.action.STATE_CHANGED";
Nick Pellybd022f42009-08-14 18:33:38 -070093
Nick Pellyde893f52009-09-08 13:15:33 -070094 /**
95 * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
96 * intents to request the current power state. Possible values are:
97 * {@link #STATE_OFF},
98 * {@link #STATE_TURNING_ON},
99 * {@link #STATE_ON},
100 * {@link #STATE_TURNING_OFF},
101 */
102 public static final String EXTRA_STATE =
Nick Pelly005b2282009-09-10 10:21:56 -0700103 "android.bluetooth.adapter.extra.STATE";
Nick Pellyde893f52009-09-08 13:15:33 -0700104 /**
105 * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
106 * intents to request the previous power state. Possible values are:
107 * {@link #STATE_OFF},
108 * {@link #STATE_TURNING_ON},
109 * {@link #STATE_ON},
110 * {@link #STATE_TURNING_OFF},
111 */
112 public static final String EXTRA_PREVIOUS_STATE =
Nick Pelly005b2282009-09-10 10:21:56 -0700113 "android.bluetooth.adapter.extra.PREVIOUS_STATE";
Nick Pellybd022f42009-08-14 18:33:38 -0700114
Nick Pellyde893f52009-09-08 13:15:33 -0700115 /**
116 * Indicates the local Bluetooth adapter is off.
117 */
Nick Pelly005b2282009-09-10 10:21:56 -0700118 public static final int STATE_OFF = 10;
Nick Pellyde893f52009-09-08 13:15:33 -0700119 /**
120 * Indicates the local Bluetooth adapter is turning on. However local
121 * clients should wait for {@link #STATE_ON} before attempting to
122 * use the adapter.
123 */
Nick Pelly005b2282009-09-10 10:21:56 -0700124 public static final int STATE_TURNING_ON = 11;
Nick Pellyde893f52009-09-08 13:15:33 -0700125 /**
126 * Indicates the local Bluetooth adapter is on, and ready for use.
127 */
Nick Pelly005b2282009-09-10 10:21:56 -0700128 public static final int STATE_ON = 12;
Nick Pellyde893f52009-09-08 13:15:33 -0700129 /**
130 * Indicates the local Bluetooth adapter is turning off. Local clients
131 * should immediately attempt graceful disconnection of any remote links.
132 */
Nick Pelly005b2282009-09-10 10:21:56 -0700133 public static final int STATE_TURNING_OFF = 13;
Nick Pellyde893f52009-09-08 13:15:33 -0700134
135 /**
Nick Pelly18b1e792009-09-24 11:14:15 -0700136 * Activity Action: Show a system activity that requests discoverable mode.
Scott Main6d95fc02009-11-19 17:00:19 -0800137 * This activity will also request the user to turn on Bluetooth if it
Nick Pelly1acdcc12009-09-28 10:33:55 -0700138 * is not currently enabled.
Nick Pelly18b1e792009-09-24 11:14:15 -0700139 * <p>Discoverable mode is equivalent to {@link
140 * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see
141 * this Bluetooth adapter when they perform a discovery.
Scott Main6d95fc02009-11-19 17:00:19 -0800142 * <p>For privacy, Android is not discoverable by default.
143 * <p>The sender of this Intent can optionally use extra field {@link
Nick Pelly18b1e792009-09-24 11:14:15 -0700144 * #EXTRA_DISCOVERABLE_DURATION} to request the duration of
145 * discoverability. Currently the default duration is 120 seconds, and
146 * maximum duration is capped at 300 seconds for each request.
147 * <p>Notification of the result of this activity is posted using the
148 * {@link android.app.Activity#onActivityResult} callback. The
149 * <code>resultCode</code>
Michael Chancdd28642009-11-05 18:29:01 -0800150 * will be the duration (in seconds) of discoverability or
151 * {@link android.app.Activity#RESULT_CANCELED} if the user rejected
152 * discoverability or an error has occurred.
Nick Pelly18b1e792009-09-24 11:14:15 -0700153 * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
Scott Main6d95fc02009-11-19 17:00:19 -0800154 * for global notification whenever the scan mode changes. For example, an
155 * application can be notified when the device has ended discoverability.
Nick Pelly1acdcc12009-09-28 10:33:55 -0700156 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
Nick Pelly18b1e792009-09-24 11:14:15 -0700157 */
158 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
159 public static final String ACTION_REQUEST_DISCOVERABLE =
160 "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
161
162 /**
163 * Used as an optional int extra field in {@link
164 * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration
165 * for discoverability in seconds. The current default is 120 seconds, and
166 * requests over 300 seconds will be capped. These values could change.
167 */
168 public static final String EXTRA_DISCOVERABLE_DURATION =
169 "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
170
171 /**
Nick Pelly1acdcc12009-09-28 10:33:55 -0700172 * Activity Action: Show a system activity that allows the user to turn on
173 * Bluetooth.
174 * <p>This system activity will return once Bluetooth has completed turning
175 * on, or the user has decided not to turn Bluetooth on.
176 * <p>Notification of the result of this activity is posted using the
177 * {@link android.app.Activity#onActivityResult} callback. The
178 * <code>resultCode</code>
Michael Chancdd28642009-11-05 18:29:01 -0800179 * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
180 * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
181 * has rejected the request or an error has occurred.
Nick Pelly1acdcc12009-09-28 10:33:55 -0700182 * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
183 * for global notification whenever Bluetooth is turned on or off.
184 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
185 */
186 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
187 public static final String ACTION_REQUEST_ENABLE =
188 "android.bluetooth.adapter.action.REQUEST_ENABLE";
189
190 /**
Nick Pellyde893f52009-09-08 13:15:33 -0700191 * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
192 * has changed.
Nick Pelly005b2282009-09-10 10:21:56 -0700193 * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
Nick Pellyde893f52009-09-08 13:15:33 -0700194 * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
195 * respectively.
196 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
197 */
198 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
199 public static final String ACTION_SCAN_MODE_CHANGED =
Nick Pelly005b2282009-09-10 10:21:56 -0700200 "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
Nick Pellyde893f52009-09-08 13:15:33 -0700201
202 /**
203 * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
204 * intents to request the current scan mode. Possible values are:
205 * {@link #SCAN_MODE_NONE},
206 * {@link #SCAN_MODE_CONNECTABLE},
207 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
208 */
Nick Pelly005b2282009-09-10 10:21:56 -0700209 public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
Nick Pellyde893f52009-09-08 13:15:33 -0700210 /**
211 * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
212 * intents to request the previous 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_PREVIOUS_SCAN_MODE =
Nick Pelly005b2282009-09-10 10:21:56 -0700218 "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
Nick Pellyde893f52009-09-08 13:15:33 -0700219
220 /**
221 * Indicates that both inquiry scan and page scan are disabled on the local
222 * Bluetooth adapter. Therefore this device is neither discoverable
223 * nor connectable from remote Bluetooth devices.
224 */
Nick Pelly005b2282009-09-10 10:21:56 -0700225 public static final int SCAN_MODE_NONE = 20;
Nick Pellyde893f52009-09-08 13:15:33 -0700226 /**
227 * Indicates that inquiry scan is disabled, but page scan is enabled on the
228 * local Bluetooth adapter. Therefore this device is not discoverable from
229 * remote Bluetooth devices, but is connectable from remote devices that
230 * have previously discovered this device.
231 */
Nick Pelly005b2282009-09-10 10:21:56 -0700232 public static final int SCAN_MODE_CONNECTABLE = 21;
Nick Pellyde893f52009-09-08 13:15:33 -0700233 /**
234 * Indicates that both inquiry scan and page scan are enabled on the local
235 * Bluetooth adapter. Therefore this device is both discoverable and
236 * connectable from remote Bluetooth devices.
237 */
Nick Pelly005b2282009-09-10 10:21:56 -0700238 public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
Nick Pellybd022f42009-08-14 18:33:38 -0700239
Nick Pelly005b2282009-09-10 10:21:56 -0700240
241 /**
242 * Broadcast Action: The local Bluetooth adapter has started the remote
243 * device discovery process.
244 * <p>This usually involves an inquiry scan of about 12 seconds, followed
245 * by a page scan of each new device to retrieve its Bluetooth name.
246 * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
247 * remote Bluetooth devices are found.
248 * <p>Device discovery is a heavyweight procedure. New connections to
249 * remote Bluetooth devices should not be attempted while discovery is in
250 * progress, and existing connections will experience limited bandwidth
251 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
252 * discovery.
253 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
254 */
255 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
256 public static final String ACTION_DISCOVERY_STARTED =
257 "android.bluetooth.adapter.action.DISCOVERY_STARTED";
258 /**
259 * Broadcast Action: The local Bluetooth adapter has finished the device
260 * discovery process.
261 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
262 */
263 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
264 public static final String ACTION_DISCOVERY_FINISHED =
265 "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
266
267 /**
268 * Broadcast Action: The local Bluetooth adapter has changed its friendly
269 * Bluetooth name.
270 * <p>This name is visible to remote Bluetooth devices.
271 * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
272 * the name.
273 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
274 */
275 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
276 public static final String ACTION_LOCAL_NAME_CHANGED =
277 "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
278 /**
279 * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
280 * intents to request the local Bluetooth name.
281 */
282 public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
283
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700284 /**
285 * Intent used to broadcast the change in connection state of the local
286 * Bluetooth adapter to a profile of the remote device. When the adapter is
287 * not connected to any profiles of any remote devices and it attempts a
288 * connection to a profile this intent will sent. Once connected, this intent
289 * will not be sent for any more connection attempts to any profiles of any
290 * remote device. When the adapter disconnects from the last profile its
291 * connected to of any remote device, this intent will be sent.
292 *
293 * <p> This intent is useful for applications that are only concerned about
294 * whether the local adapter is connected to any profile of any device and
295 * are not really concerned about which profile. For example, an application
296 * which displays an icon to display whether Bluetooth is connected or not
297 * can use this intent.
298 *
299 * <p>This intent will have 3 extras:
Jaikumar Ganesh0b5b35f2011-02-01 16:47:11 -0800300 * {@link #EXTRA_CONNECTION_STATE} - The current connection state.
301 * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700302 * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
303 *
Jaikumar Ganesh0b5b35f2011-02-01 16:47:11 -0800304 * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE}
305 * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700306 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
307 *
308 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
309 */
310 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
311 public static final String ACTION_CONNECTION_STATE_CHANGED =
312 "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
313
314 /**
315 * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
316 *
317 * This extra represents the current connection state.
318 */
319 public static final String EXTRA_CONNECTION_STATE =
320 "android.bluetooth.adapter.extra.CONNECTION_STATE";
321
322 /**
323 * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
324 *
325 * This extra represents the previous connection state.
326 */
327 public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
328 "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
329
330 /** The profile is in disconnected state */
331 public static final int STATE_DISCONNECTED = 0;
332 /** The profile is in connecting state */
333 public static final int STATE_CONNECTING = 1;
334 /** The profile is in connected state */
335 public static final int STATE_CONNECTED = 2;
336 /** The profile is in disconnecting state */
337 public static final int STATE_DISCONNECTING = 3;
338
Nick Pellyf242b7b2009-10-08 00:12:45 +0200339 /** @hide */
340 public static final String BLUETOOTH_SERVICE = "bluetooth";
341
Nick Pelly005b2282009-09-10 10:21:56 -0700342 private static final int ADDRESS_LENGTH = 17;
Nick Pellybd022f42009-08-14 18:33:38 -0700343
Nick Pellyf242b7b2009-10-08 00:12:45 +0200344 /**
Jake Hambyf51eada2010-09-21 13:39:53 -0700345 * Lazily initialized singleton. Guaranteed final after first object
Nick Pellyf242b7b2009-10-08 00:12:45 +0200346 * constructed.
347 */
348 private static BluetoothAdapter sAdapter;
349
Nick Pellybd022f42009-08-14 18:33:38 -0700350 private final IBluetooth mService;
351
Matthew Xie484867a2011-08-25 16:45:58 -0700352 private Handler mServiceRecordHandler;
353
Nick Pellybd022f42009-08-14 18:33:38 -0700354 /**
Nick Pellyf242b7b2009-10-08 00:12:45 +0200355 * Get a handle to the default local Bluetooth adapter.
356 * <p>Currently Android only supports one Bluetooth adapter, but the API
357 * could be extended to support more. This will always return the default
358 * adapter.
359 * @return the default local adapter, or null if Bluetooth is not supported
360 * on this hardware platform
361 */
362 public static synchronized BluetoothAdapter getDefaultAdapter() {
363 if (sAdapter == null) {
364 IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
365 if (b != null) {
366 IBluetooth service = IBluetooth.Stub.asInterface(b);
367 sAdapter = new BluetoothAdapter(service);
368 }
369 }
370 return sAdapter;
371 }
372
373 /**
374 * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
Nick Pellybd022f42009-08-14 18:33:38 -0700375 * @hide
376 */
377 public BluetoothAdapter(IBluetooth service) {
378 if (service == null) {
379 throw new IllegalArgumentException("service is null");
380 }
381 mService = service;
Matthew Xie484867a2011-08-25 16:45:58 -0700382 mServiceRecordHandler = null;
Nick Pellybd022f42009-08-14 18:33:38 -0700383 }
384
385 /**
Nick Pelly45e27042009-08-19 11:00:00 -0700386 * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
387 * address.
388 * <p>Valid Bluetooth hardware addresses must be upper case, in a format
Nick Pelly005b2282009-09-10 10:21:56 -0700389 * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
390 * available to validate a Bluetooth address.
Nick Pelly45e27042009-08-19 11:00:00 -0700391 * <p>A {@link BluetoothDevice} will always be returned for a valid
392 * hardware address, even if this adapter has never seen that device.
Nick Pellyde893f52009-09-08 13:15:33 -0700393 *
Nick Pellybd022f42009-08-14 18:33:38 -0700394 * @param address valid Bluetooth MAC address
Nick Pelly45e27042009-08-19 11:00:00 -0700395 * @throws IllegalArgumentException if address is invalid
Nick Pellybd022f42009-08-14 18:33:38 -0700396 */
397 public BluetoothDevice getRemoteDevice(String address) {
398 return new BluetoothDevice(address);
399 }
400
401 /**
Nick Pelly75596b42011-12-07 15:03:55 -0800402 * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
403 * address.
404 * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method
405 * expects the address in network byte order (MSB first).
406 * <p>A {@link BluetoothDevice} will always be returned for a valid
407 * hardware address, even if this adapter has never seen that device.
408 *
409 * @param address Bluetooth MAC address (6 bytes)
410 * @throws IllegalArgumentException if address is invalid
411 */
412 public BluetoothDevice getRemoteDevice(byte[] address) {
413 if (address == null || address.length != 6) {
414 throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
415 }
416 return new BluetoothDevice(String.format("%02X:%02X:%02X:%02X:%02X:%02X",
417 address[0], address[1], address[2], address[3], address[4], address[5]));
418 }
419
420 /**
Nick Pellyde893f52009-09-08 13:15:33 -0700421 * Return true if Bluetooth is currently enabled and ready for use.
422 * <p>Equivalent to:
423 * <code>getBluetoothState() == STATE_ON</code>
424 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
Nick Pellybd022f42009-08-14 18:33:38 -0700425 *
Nick Pellyde893f52009-09-08 13:15:33 -0700426 * @return true if the local adapter is turned on
Nick Pellybd022f42009-08-14 18:33:38 -0700427 */
428 public boolean isEnabled() {
429 try {
430 return mService.isEnabled();
431 } catch (RemoteException e) {Log.e(TAG, "", e);}
432 return false;
433 }
434
435 /**
Nick Pellyde893f52009-09-08 13:15:33 -0700436 * Get the current state of the local Bluetooth adapter.
437 * <p>Possible return values are
438 * {@link #STATE_OFF},
439 * {@link #STATE_TURNING_ON},
440 * {@link #STATE_ON},
441 * {@link #STATE_TURNING_OFF}.
442 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
Nick Pellybd022f42009-08-14 18:33:38 -0700443 *
Nick Pellyde893f52009-09-08 13:15:33 -0700444 * @return current state of Bluetooth adapter
Nick Pellybd022f42009-08-14 18:33:38 -0700445 */
Nick Pellyde893f52009-09-08 13:15:33 -0700446 public int getState() {
Nick Pellybd022f42009-08-14 18:33:38 -0700447 try {
448 return mService.getBluetoothState();
449 } catch (RemoteException e) {Log.e(TAG, "", e);}
Nick Pellyde893f52009-09-08 13:15:33 -0700450 return STATE_OFF;
Nick Pellybd022f42009-08-14 18:33:38 -0700451 }
452
453 /**
Scott Mained2a70d2009-12-09 16:07:39 -0800454 * Turn on the local Bluetooth adapter&mdash;do not use without explicit
455 * user action to turn on Bluetooth.
Nick Pellyde893f52009-09-08 13:15:33 -0700456 * <p>This powers on the underlying Bluetooth hardware, and starts all
457 * Bluetooth system services.
Scott Mained2a70d2009-12-09 16:07:39 -0800458 * <p class="caution"><strong>Bluetooth should never be enabled without
459 * direct user consent</strong>. If you want to turn on Bluetooth in order
460 * to create a wireless connection, you should use the {@link
461 * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
462 * user permission to turn on Bluetooth. The {@link #enable()} method is
463 * provided only for applications that include a user interface for changing
464 * system settings, such as a "power manager" app.</p>
Brad Fitzpatrick3219ab42009-09-25 16:31:39 +0400465 * <p>This is an asynchronous call: it will return immediately, and
Nick Pellyde893f52009-09-08 13:15:33 -0700466 * clients should listen for {@link #ACTION_STATE_CHANGED}
467 * to be notified of subsequent adapter state changes. If this call returns
468 * true, then the adapter state will immediately transition from {@link
469 * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
470 * later transition to either {@link #STATE_OFF} or {@link
471 * #STATE_ON}. If this call returns false then there was an
472 * immediate problem that will prevent the adapter from being turned on -
473 * such as Airplane mode, or the adapter is already turned on.
Scott Mained2a70d2009-12-09 16:07:39 -0800474 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
475 * permission
Nick Pellyde893f52009-09-08 13:15:33 -0700476 *
477 * @return true to indicate adapter startup has begun, or false on
478 * immediate error
Nick Pellybd022f42009-08-14 18:33:38 -0700479 */
480 public boolean enable() {
481 try {
482 return mService.enable();
483 } catch (RemoteException e) {Log.e(TAG, "", e);}
484 return false;
485 }
486
487 /**
Scott Mained2a70d2009-12-09 16:07:39 -0800488 * Turn off the local Bluetooth adapter&mdash;do not use without explicit
489 * user action to turn off Bluetooth.
Nick Pellyde893f52009-09-08 13:15:33 -0700490 * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
491 * system services, and powers down the underlying Bluetooth hardware.
Jake Hambyf51eada2010-09-21 13:39:53 -0700492 * <p class="caution"><strong>Bluetooth should never be disabled without
Scott Mained2a70d2009-12-09 16:07:39 -0800493 * direct user consent</strong>. The {@link #disable()} method is
494 * provided only for applications that include a user interface for changing
495 * system settings, such as a "power manager" app.</p>
Brad Fitzpatrick3219ab42009-09-25 16:31:39 +0400496 * <p>This is an asynchronous call: it will return immediately, and
Nick Pellyde893f52009-09-08 13:15:33 -0700497 * clients should listen for {@link #ACTION_STATE_CHANGED}
498 * to be notified of subsequent adapter state changes. If this call returns
499 * true, then the adapter state will immediately transition from {@link
500 * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
501 * later transition to either {@link #STATE_OFF} or {@link
502 * #STATE_ON}. If this call returns false then there was an
503 * immediate problem that will prevent the adapter from being turned off -
504 * such as the adapter already being turned off.
Scott Mained2a70d2009-12-09 16:07:39 -0800505 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
506 * permission
Nick Pellybd022f42009-08-14 18:33:38 -0700507 *
Nick Pellyde893f52009-09-08 13:15:33 -0700508 * @return true to indicate adapter shutdown has begun, or false on
509 * immediate error
Nick Pellybd022f42009-08-14 18:33:38 -0700510 */
511 public boolean disable() {
512 try {
513 return mService.disable(true);
514 } catch (RemoteException e) {Log.e(TAG, "", e);}
515 return false;
516 }
517
Nick Pellyde893f52009-09-08 13:15:33 -0700518 /**
519 * Returns the hardware address of the local Bluetooth adapter.
520 * <p>For example, "00:11:22:AA:BB:CC".
521 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
522 *
523 * @return Bluetooth hardware address as string
524 */
Nick Pellybd022f42009-08-14 18:33:38 -0700525 public String getAddress() {
526 try {
527 return mService.getAddress();
528 } catch (RemoteException e) {Log.e(TAG, "", e);}
529 return null;
530 }
531
532 /**
Nick Pellyde893f52009-09-08 13:15:33 -0700533 * Get the friendly Bluetooth name of the local Bluetooth adapter.
534 * <p>This name is visible to remote Bluetooth devices.
535 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
Nick Pellybd022f42009-08-14 18:33:38 -0700536 *
Nick Pellyde893f52009-09-08 13:15:33 -0700537 * @return the Bluetooth name, or null on error
Nick Pellybd022f42009-08-14 18:33:38 -0700538 */
539 public String getName() {
540 try {
541 return mService.getName();
542 } catch (RemoteException e) {Log.e(TAG, "", e);}
543 return null;
544 }
545
546 /**
Jaikumar Ganesh58b93c32010-11-23 20:03:10 -0800547 * Get the UUIDs supported by the local Bluetooth adapter.
548 *
549 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
550 *
551 * @return the UUIDs supported by the local Bluetooth Adapter.
552 * @hide
553 */
554 public ParcelUuid[] getUuids() {
Matthew Xie44b58ab2011-11-16 12:27:57 -0800555 if (getState() != STATE_ON) return null;
Jaikumar Ganesh58b93c32010-11-23 20:03:10 -0800556 try {
557 return mService.getUuids();
558 } catch (RemoteException e) {Log.e(TAG, "", e);}
559 return null;
560 }
561
562 /**
Jake Hamby0f584302010-09-16 18:12:51 -0700563 * Set the friendly Bluetooth name of the local Bluetooth adapter.
Nick Pellyde893f52009-09-08 13:15:33 -0700564 * <p>This name is visible to remote Bluetooth devices.
Jake Hamby0f584302010-09-16 18:12:51 -0700565 * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
566 * encoding, although many remote devices can only display the first
567 * 40 characters, and some may be limited to just 20.
Jaikumar Ganeshfec86f42010-08-09 16:54:03 -0700568 * <p>If Bluetooth state is not {@link #STATE_ON}, this API
569 * will return false. After turning on Bluetooth,
570 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
571 * to get the updated value.
Nick Pellyde893f52009-09-08 13:15:33 -0700572 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
Nick Pellybd022f42009-08-14 18:33:38 -0700573 *
Nick Pellyde893f52009-09-08 13:15:33 -0700574 * @param name a valid Bluetooth name
575 * @return true if the name was set, false otherwise
Nick Pellybd022f42009-08-14 18:33:38 -0700576 */
577 public boolean setName(String name) {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700578 if (getState() != STATE_ON) return false;
Nick Pellybd022f42009-08-14 18:33:38 -0700579 try {
580 return mService.setName(name);
581 } catch (RemoteException e) {Log.e(TAG, "", e);}
582 return false;
583 }
584
585 /**
Jake Hamby0f584302010-09-16 18:12:51 -0700586 * Get the current Bluetooth scan mode of the local Bluetooth adapter.
Nick Pellyde893f52009-09-08 13:15:33 -0700587 * <p>The Bluetooth scan mode determines if the local adapter is
588 * connectable and/or discoverable from remote Bluetooth devices.
589 * <p>Possible values are:
590 * {@link #SCAN_MODE_NONE},
591 * {@link #SCAN_MODE_CONNECTABLE},
592 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
Jaikumar Ganeshfec86f42010-08-09 16:54:03 -0700593 * <p>If Bluetooth state is not {@link #STATE_ON}, this API
594 * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
595 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
596 * to get the updated value.
Nick Pellyde893f52009-09-08 13:15:33 -0700597 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
598 *
599 * @return scan mode
Nick Pellybd022f42009-08-14 18:33:38 -0700600 */
601 public int getScanMode() {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700602 if (getState() != STATE_ON) return SCAN_MODE_NONE;
Nick Pellybd022f42009-08-14 18:33:38 -0700603 try {
604 return mService.getScanMode();
605 } catch (RemoteException e) {Log.e(TAG, "", e);}
Nick Pellyde893f52009-09-08 13:15:33 -0700606 return SCAN_MODE_NONE;
Nick Pellybd022f42009-08-14 18:33:38 -0700607 }
608
609 /**
Nick Pellyde893f52009-09-08 13:15:33 -0700610 * Set the Bluetooth scan mode of the local Bluetooth adapter.
611 * <p>The Bluetooth scan mode determines if the local adapter is
612 * connectable and/or discoverable from remote Bluetooth devices.
Nick Pelly12835472009-09-25 15:00:29 -0700613 * <p>For privacy reasons, discoverable mode is automatically turned off
614 * after <code>duration</code> seconds. For example, 120 seconds should be
615 * enough for a remote device to initiate and complete its discovery
616 * process.
Nick Pellyde893f52009-09-08 13:15:33 -0700617 * <p>Valid scan mode values are:
618 * {@link #SCAN_MODE_NONE},
619 * {@link #SCAN_MODE_CONNECTABLE},
620 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
Jaikumar Ganeshfec86f42010-08-09 16:54:03 -0700621 * <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.
Nick Pelly18b1e792009-09-24 11:14:15 -0700625 * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
626 * <p>Applications cannot set the scan mode. They should use
627 * <code>startActivityForResult(
628 * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
629 * </code>instead.
Nick Pellyde893f52009-09-08 13:15:33 -0700630 *
631 * @param mode valid scan mode
Nick Pelly12835472009-09-25 15:00:29 -0700632 * @param duration time in seconds to apply scan mode, only used for
633 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
Nick Pellyde893f52009-09-08 13:15:33 -0700634 * @return true if the scan mode was set, false otherwise
Nick Pelly18b1e792009-09-24 11:14:15 -0700635 * @hide
Nick Pellybd022f42009-08-14 18:33:38 -0700636 */
Nick Pelly12835472009-09-25 15:00:29 -0700637 public boolean setScanMode(int mode, int duration) {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700638 if (getState() != STATE_ON) return false;
Nick Pellybd022f42009-08-14 18:33:38 -0700639 try {
Nick Pelly12835472009-09-25 15:00:29 -0700640 return mService.setScanMode(mode, duration);
Nick Pellybd022f42009-08-14 18:33:38 -0700641 } catch (RemoteException e) {Log.e(TAG, "", e);}
Nick Pellyde893f52009-09-08 13:15:33 -0700642 return false;
Nick Pellybd022f42009-08-14 18:33:38 -0700643 }
644
Nick Pelly45e27042009-08-19 11:00:00 -0700645 /** @hide */
Nick Pelly12835472009-09-25 15:00:29 -0700646 public boolean setScanMode(int mode) {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700647 if (getState() != STATE_ON) return false;
Nick Pelly12835472009-09-25 15:00:29 -0700648 return setScanMode(mode, 120);
649 }
650
651 /** @hide */
Nick Pellybd022f42009-08-14 18:33:38 -0700652 public int getDiscoverableTimeout() {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700653 if (getState() != STATE_ON) return -1;
Nick Pellybd022f42009-08-14 18:33:38 -0700654 try {
655 return mService.getDiscoverableTimeout();
656 } catch (RemoteException e) {Log.e(TAG, "", e);}
657 return -1;
658 }
659
Nick Pelly45e27042009-08-19 11:00:00 -0700660 /** @hide */
Nick Pellybd022f42009-08-14 18:33:38 -0700661 public void setDiscoverableTimeout(int timeout) {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700662 if (getState() != STATE_ON) return;
Nick Pellybd022f42009-08-14 18:33:38 -0700663 try {
664 mService.setDiscoverableTimeout(timeout);
665 } catch (RemoteException e) {Log.e(TAG, "", e);}
666 }
667
Nick Pelly005b2282009-09-10 10:21:56 -0700668 /**
669 * Start the remote device discovery process.
670 * <p>The discovery process usually involves an inquiry scan of about 12
671 * seconds, followed by a page scan of each new device to retrieve its
672 * Bluetooth name.
673 * <p>This is an asynchronous call, it will return immediately. Register
674 * for {@link #ACTION_DISCOVERY_STARTED} and {@link
675 * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
676 * discovery starts and completes. Register for {@link
677 * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
678 * are found.
679 * <p>Device discovery is a heavyweight procedure. New connections to
680 * remote Bluetooth devices should not be attempted while discovery is in
681 * progress, and existing connections will experience limited bandwidth
682 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
Scott Main6d95fc02009-11-19 17:00:19 -0800683 * discovery. Discovery is not managed by the Activity,
684 * but is run as a system service, so an application should always call
685 * {@link BluetoothAdapter#cancelDiscovery()} even if it
686 * did not directly request a discovery, just to be sure.
Nick Pelly005b2282009-09-10 10:21:56 -0700687 * <p>Device discovery will only find remote devices that are currently
688 * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
689 * not discoverable by default, and need to be entered into a special mode.
Jaikumar Ganeshfec86f42010-08-09 16:54:03 -0700690 * <p>If Bluetooth state is not {@link #STATE_ON}, this API
691 * will return false. After turning on Bluetooth,
692 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
693 * to get the updated value.
Nick Pelly005b2282009-09-10 10:21:56 -0700694 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
695 *
696 * @return true on success, false on error
697 */
Nick Pellybd022f42009-08-14 18:33:38 -0700698 public boolean startDiscovery() {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700699 if (getState() != STATE_ON) return false;
Nick Pellybd022f42009-08-14 18:33:38 -0700700 try {
701 return mService.startDiscovery();
702 } catch (RemoteException e) {Log.e(TAG, "", e);}
703 return false;
704 }
705
Nick Pelly005b2282009-09-10 10:21:56 -0700706 /**
707 * Cancel the current device discovery process.
708 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
Jake Hamby0f584302010-09-16 18:12:51 -0700709 * <p>Because discovery is a heavyweight procedure for the Bluetooth
Scott Main6d95fc02009-11-19 17:00:19 -0800710 * adapter, this method should always be called before attempting to connect
711 * to a remote device with {@link
712 * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
713 * the Activity, but is run as a system service, so an application should
714 * always call cancel discovery even if it did not directly request a
715 * discovery, just to be sure.
Jaikumar Ganeshfec86f42010-08-09 16:54:03 -0700716 * <p>If Bluetooth state is not {@link #STATE_ON}, this API
717 * will return false. After turning on Bluetooth,
718 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
719 * to get the updated value.
Nick Pelly005b2282009-09-10 10:21:56 -0700720 *
721 * @return true on success, false on error
722 */
723 public boolean cancelDiscovery() {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700724 if (getState() != STATE_ON) return false;
Nick Pellybd022f42009-08-14 18:33:38 -0700725 try {
Albert Mojirefc1d162011-03-21 14:59:10 +0100726 return mService.cancelDiscovery();
Nick Pellybd022f42009-08-14 18:33:38 -0700727 } catch (RemoteException e) {Log.e(TAG, "", e);}
Nick Pelly005b2282009-09-10 10:21:56 -0700728 return false;
Nick Pellybd022f42009-08-14 18:33:38 -0700729 }
730
Nick Pelly005b2282009-09-10 10:21:56 -0700731 /**
732 * Return true if the local Bluetooth adapter is currently in the device
733 * discovery process.
734 * <p>Device discovery is a heavyweight procedure. New connections to
735 * remote Bluetooth devices should not be attempted while discovery is in
736 * progress, and existing connections will experience limited bandwidth
737 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
738 * discovery.
739 * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
740 * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
741 * starts or completes.
Jaikumar Ganeshfec86f42010-08-09 16:54:03 -0700742 * <p>If Bluetooth state is not {@link #STATE_ON}, this API
743 * will return false. After turning on Bluetooth,
744 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
745 * to get the updated value.
Nick Pellye6ee3be2009-10-08 23:27:28 +0200746 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
Nick Pelly005b2282009-09-10 10:21:56 -0700747 *
748 * @return true if discovering
749 */
Nick Pellybd022f42009-08-14 18:33:38 -0700750 public boolean isDiscovering() {
Jaikumar Ganeshf5ff1702010-08-06 19:03:13 -0700751 if (getState() != STATE_ON) return false;
Nick Pellybd022f42009-08-14 18:33:38 -0700752 try {
753 return mService.isDiscovering();
754 } catch (RemoteException e) {Log.e(TAG, "", e);}
755 return false;
756 }
757
758 /**
Nick Pelly005b2282009-09-10 10:21:56 -0700759 * Return the set of {@link BluetoothDevice} objects that are bonded
760 * (paired) to the local adapter.
Jaikumar Ganeshfec86f42010-08-09 16:54:03 -0700761 * <p>If Bluetooth state is not {@link #STATE_ON}, this API
762 * will return an empty set. After turning on Bluetooth,
763 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
764 * to get the updated value.
Nick Pellye6ee3be2009-10-08 23:27:28 +0200765 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
Nick Pellybd022f42009-08-14 18:33:38 -0700766 *
Nick Pelly005b2282009-09-10 10:21:56 -0700767 * @return unmodifiable set of {@link BluetoothDevice}, or null on error
Nick Pellybd022f42009-08-14 18:33:38 -0700768 */
769 public Set<BluetoothDevice> getBondedDevices() {
Jaikumar Ganeshfec86f42010-08-09 16:54:03 -0700770 if (getState() != STATE_ON) {
771 return toDeviceSet(new String[0]);
772 }
Nick Pellybd022f42009-08-14 18:33:38 -0700773 try {
774 return toDeviceSet(mService.listBonds());
775 } catch (RemoteException e) {Log.e(TAG, "", e);}
776 return null;
777 }
778
779 /**
Jaikumar Ganeshc53cab22010-10-26 16:02:26 -0700780 * Get the current connection state of the local Bluetooth adapter.
781 * This can be used to check whether the local Bluetooth adapter is connected
782 * to any profile of any other remote Bluetooth Device.
783 *
784 * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
785 * intent to get the connection state of the adapter.
786 *
787 * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED},
788 * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
789 *
790 * @hide
791 */
792 public int getConnectionState() {
793 if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
794 try {
795 return mService.getAdapterConnectionState();
796 } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
797 return BluetoothAdapter.STATE_DISCONNECTED;
798 }
799
800 /**
Jaikumar Ganeshcb1d3542011-08-19 10:26:32 -0700801 * Get the current connection state of a profile.
802 * This function can be used to check whether the local Bluetooth adapter
803 * is connected to any remote device for a specific profile.
Scott Main2d68a6b2011-09-26 22:59:38 -0700804 * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
Jaikumar Ganesh93547902011-08-23 12:21:55 -0700805 * {@link BluetoothProfile#A2DP}.
Jaikumar Ganeshcb1d3542011-08-19 10:26:32 -0700806 *
807 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
808 *
809 * <p> Return value can be one of
Jaikumar Ganesh93547902011-08-23 12:21:55 -0700810 * {@link BluetoothProfile#STATE_DISCONNECTED},
811 * {@link BluetoothProfile#STATE_CONNECTING},
812 * {@link BluetoothProfile#STATE_CONNECTED},
813 * {@link BluetoothProfile#STATE_DISCONNECTING}
Jaikumar Ganeshcb1d3542011-08-19 10:26:32 -0700814 */
815 public int getProfileConnectionState(int profile) {
816 if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
817 try {
818 return mService.getProfileConnectionState(profile);
Jaikumar Ganesh93547902011-08-23 12:21:55 -0700819 } catch (RemoteException e) {
820 Log.e(TAG, "getProfileConnectionState:", e);
821 }
Jaikumar Ganeshcb1d3542011-08-19 10:26:32 -0700822 return BluetoothProfile.STATE_DISCONNECTED;
823 }
824
825 /**
826 /**
Nick Pelly16fb88a2009-10-07 07:44:03 +0200827 * Picks RFCOMM channels until none are left.
Nick Pelly24bb9b82009-10-02 20:34:18 -0700828 * Avoids reserved channels.
829 */
830 private static class RfcommChannelPicker {
831 private static final int[] RESERVED_RFCOMM_CHANNELS = new int[] {
832 10, // HFAG
833 11, // HSAG
834 12, // OPUSH
835 19, // PBAP
836 };
837 private static LinkedList<Integer> sChannels; // master list of non-reserved channels
838 private static Random sRandom;
839
840 private final LinkedList<Integer> mChannels; // local list of channels left to try
841
Nick Pelly16fb88a2009-10-07 07:44:03 +0200842 private final UUID mUuid;
843
844 public RfcommChannelPicker(UUID uuid) {
Nick Pelly24bb9b82009-10-02 20:34:18 -0700845 synchronized (RfcommChannelPicker.class) {
846 if (sChannels == null) {
847 // lazy initialization of non-reserved rfcomm channels
848 sChannels = new LinkedList<Integer>();
849 for (int i = 1; i <= BluetoothSocket.MAX_RFCOMM_CHANNEL; i++) {
850 sChannels.addLast(new Integer(i));
851 }
852 for (int reserved : RESERVED_RFCOMM_CHANNELS) {
853 sChannels.remove(new Integer(reserved));
854 }
855 sRandom = new Random();
856 }
857 mChannels = (LinkedList<Integer>)sChannels.clone();
858 }
Nick Pelly16fb88a2009-10-07 07:44:03 +0200859 mUuid = uuid;
Nick Pelly24bb9b82009-10-02 20:34:18 -0700860 }
Jaikumar Ganesh4b3db902009-10-30 09:37:25 -0700861 /* Returns next random channel, or -1 if we're out */
Nick Pelly24bb9b82009-10-02 20:34:18 -0700862 public int nextChannel() {
Jaikumar Ganesh4b3db902009-10-30 09:37:25 -0700863 if (mChannels.size() == 0) {
864 return -1;
Nick Pelly24bb9b82009-10-02 20:34:18 -0700865 }
Jaikumar Ganesh4b3db902009-10-30 09:37:25 -0700866 return mChannels.remove(sRandom.nextInt(mChannels.size()));
Nick Pelly24bb9b82009-10-02 20:34:18 -0700867 }
868 }
869
870 /**
Nick Pelly45e27042009-08-19 11:00:00 -0700871 * Create a listening, secure RFCOMM Bluetooth socket.
872 * <p>A remote device connecting to this socket will be authenticated and
Nick Pellybd022f42009-08-14 18:33:38 -0700873 * communication on this socket will be encrypted.
Nick Pelly45e27042009-08-19 11:00:00 -0700874 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
Nick Pelly24bb9b82009-10-02 20:34:18 -0700875 * connections from a listening {@link BluetoothServerSocket}.
Nick Pelly45e27042009-08-19 11:00:00 -0700876 * <p>Valid RFCOMM channels are in range 1 to 30.
Nick Pelly24bb9b82009-10-02 20:34:18 -0700877 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
Nick Pelly45e27042009-08-19 11:00:00 -0700878 * @param channel RFCOMM channel to listen on
879 * @return a listening RFCOMM BluetoothServerSocket
880 * @throws IOException on error, for example Bluetooth not available, or
881 * insufficient permissions, or channel in use.
Nick Pelly24bb9b82009-10-02 20:34:18 -0700882 * @hide
Nick Pellybd022f42009-08-14 18:33:38 -0700883 */
Nick Pelly45e27042009-08-19 11:00:00 -0700884 public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
Nick Pellybd022f42009-08-14 18:33:38 -0700885 BluetoothServerSocket socket = new BluetoothServerSocket(
Nick Pelly45e27042009-08-19 11:00:00 -0700886 BluetoothSocket.TYPE_RFCOMM, true, true, channel);
Nick Pelly24bb9b82009-10-02 20:34:18 -0700887 int errno = socket.mSocket.bindListen();
888 if (errno != 0) {
Nick Pellybd022f42009-08-14 18:33:38 -0700889 try {
890 socket.close();
Nick Pelly24bb9b82009-10-02 20:34:18 -0700891 } catch (IOException e) {}
892 socket.mSocket.throwErrnoNative(errno);
Nick Pellybd022f42009-08-14 18:33:38 -0700893 }
894 return socket;
895 }
896
897 /**
Nick Pelly24bb9b82009-10-02 20:34:18 -0700898 * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
899 * <p>A remote device connecting to this socket will be authenticated and
900 * communication on this socket will be encrypted.
901 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
902 * connections from a listening {@link BluetoothServerSocket}.
903 * <p>The system will assign an unused RFCOMM channel to listen on.
904 * <p>The system will also register a Service Discovery
905 * Protocol (SDP) record with the local SDP server containing the specified
906 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
907 * can use the same UUID to query our SDP server and discover which channel
908 * to connect to. This SDP record will be removed when this socket is
909 * closed, or if this application closes unexpectedly.
Nick Pelly16fb88a2009-10-07 07:44:03 +0200910 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
911 * connect to this socket from another device using the same {@link UUID}.
Nick Pelly24bb9b82009-10-02 20:34:18 -0700912 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
913 * @param name service name for SDP record
914 * @param uuid uuid for SDP record
915 * @return a listening RFCOMM BluetoothServerSocket
916 * @throws IOException on error, for example Bluetooth not available, or
917 * insufficient permissions, or channel in use.
918 */
Nick Pelly16fb88a2009-10-07 07:44:03 +0200919 public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
Nick Pelly24bb9b82009-10-02 20:34:18 -0700920 throws IOException {
Jaikumar Ganesh6eef14a2010-12-23 12:57:02 -0800921 return createNewRfcommSocketAndRecord(name, uuid, true, true);
922 }
923
924 /**
925 * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
Mathias Jeppssone3b9dc102011-03-21 15:06:52 +0100926 * <p>The link key is not required to be authenticated, i.e the communication may be
Jaikumar Ganesh6eef14a2010-12-23 12:57:02 -0800927 * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
Mathias Jeppssone3b9dc102011-03-21 15:06:52 +0100928 * the link will be encrypted, as encryption is mandartory.
929 * For legacy devices (pre Bluetooth 2.1 devices) the link will not
Jaikumar Ganesh6eef14a2010-12-23 12:57:02 -0800930 * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
931 * encrypted and authenticated communication channel is desired.
932 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
933 * connections from a listening {@link BluetoothServerSocket}.
934 * <p>The system will assign an unused RFCOMM channel to listen on.
935 * <p>The system will also register a Service Discovery
936 * Protocol (SDP) record with the local SDP server containing the specified
937 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
938 * can use the same UUID to query our SDP server and discover which channel
939 * to connect to. This SDP record will be removed when this socket is
940 * closed, or if this application closes unexpectedly.
941 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
942 * connect to this socket from another device using the same {@link UUID}.
943 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
944 * @param name service name for SDP record
945 * @param uuid uuid for SDP record
946 * @return a listening RFCOMM BluetoothServerSocket
947 * @throws IOException on error, for example Bluetooth not available, or
948 * insufficient permissions, or channel in use.
949 */
950 public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
951 throws IOException {
952 return createNewRfcommSocketAndRecord(name, uuid, false, false);
953 }
954
Mathias Jeppssone3b9dc102011-03-21 15:06:52 +0100955 /**
956 * Create a listening, encrypted,
957 * RFCOMM Bluetooth socket with Service Record.
958 * <p>The link will be encrypted, but the link key is not required to be authenticated
959 * i.e the communication is vulnerable to Man In the Middle attacks. Use
960 * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
961 * <p> Use this socket if authentication of link key is not possible.
962 * For example, for Bluetooth 2.1 devices, if any of the devices does not have
963 * an input and output capability or just has the ability to display a numeric key,
964 * a secure socket connection is not possible and this socket can be used.
965 * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
966 * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory.
967 * For more details, refer to the Security Model section 5.2 (vol 3) of
968 * Bluetooth Core Specification version 2.1 + EDR.
969 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
970 * connections from a listening {@link BluetoothServerSocket}.
971 * <p>The system will assign an unused RFCOMM channel to listen on.
972 * <p>The system will also register a Service Discovery
973 * Protocol (SDP) record with the local SDP server containing the specified
974 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
975 * can use the same UUID to query our SDP server and discover which channel
976 * to connect to. This SDP record will be removed when this socket is
977 * closed, or if this application closes unexpectedly.
978 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
979 * connect to this socket from another device using the same {@link UUID}.
980 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
981 * @param name service name for SDP record
982 * @param uuid uuid for SDP record
983 * @return a listening RFCOMM BluetoothServerSocket
984 * @throws IOException on error, for example Bluetooth not available, or
985 * insufficient permissions, or channel in use.
986 * @hide
987 */
988 public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
989 String name, UUID uuid) throws IOException {
990 return createNewRfcommSocketAndRecord(name, uuid, false, true);
991 }
992
Jaikumar Ganesh6eef14a2010-12-23 12:57:02 -0800993 private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
994 boolean auth, boolean encrypt) throws IOException {
Nick Pelly16fb88a2009-10-07 07:44:03 +0200995 RfcommChannelPicker picker = new RfcommChannelPicker(uuid);
Nick Pelly24bb9b82009-10-02 20:34:18 -0700996
997 BluetoothServerSocket socket;
998 int channel;
999 int errno;
1000 while (true) {
1001 channel = picker.nextChannel();
1002
1003 if (channel == -1) {
1004 throw new IOException("No available channels");
1005 }
1006
1007 socket = new BluetoothServerSocket(
Jaikumar Ganesh6eef14a2010-12-23 12:57:02 -08001008 BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel);
Nick Pelly24bb9b82009-10-02 20:34:18 -07001009 errno = socket.mSocket.bindListen();
1010 if (errno == 0) {
1011 if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel);
1012 break; // success
1013 } else if (errno == BluetoothSocket.EADDRINUSE) {
1014 if (DBG) Log.d(TAG, "RFCOMM channel " + channel + " in use");
1015 try {
1016 socket.close();
1017 } catch (IOException e) {}
1018 continue; // try another channel
1019 } else {
1020 try {
1021 socket.close();
1022 } catch (IOException e) {}
1023 socket.mSocket.throwErrnoNative(errno); // Exception as a result of bindListen()
1024 }
1025 }
1026
1027 int handle = -1;
1028 try {
Nick Pelly16fb88a2009-10-07 07:44:03 +02001029 handle = mService.addRfcommServiceRecord(name, new ParcelUuid(uuid), channel,
1030 new Binder());
Nick Pelly24bb9b82009-10-02 20:34:18 -07001031 } catch (RemoteException e) {Log.e(TAG, "", e);}
1032 if (handle == -1) {
1033 try {
1034 socket.close();
1035 } catch (IOException e) {}
1036 throw new IOException("Not able to register SDP record for " + name);
1037 }
Matthew Xie484867a2011-08-25 16:45:58 -07001038
1039 if (mServiceRecordHandler == null) {
1040 mServiceRecordHandler = new Handler(Looper.getMainLooper()) {
1041 public void handleMessage(Message msg) {
1042 /* handle socket closing */
1043 int handle = msg.what;
1044 try {
1045 if (DBG) Log.d(TAG, "Removing service record " +
1046 Integer.toHexString(handle));
1047 mService.removeServiceRecord(handle);
1048 } catch (RemoteException e) {Log.e(TAG, "", e);}
1049 }
1050 };
1051 }
1052 socket.setCloseHandler(mServiceRecordHandler, handle);
Nick Pelly24bb9b82009-10-02 20:34:18 -07001053 return socket;
1054 }
1055
Jaikumar Ganeshc53cab22010-10-26 16:02:26 -07001056
Nick Pelly24bb9b82009-10-02 20:34:18 -07001057 /**
Nick Pellybd022f42009-08-14 18:33:38 -07001058 * Construct an unencrypted, unauthenticated, RFCOMM server socket.
1059 * Call #accept to retrieve connections to this socket.
1060 * @return An RFCOMM BluetoothServerSocket
1061 * @throws IOException On error, for example Bluetooth not available, or
1062 * insufficient permissions.
Nick Pelly45e27042009-08-19 11:00:00 -07001063 * @hide
Nick Pellybd022f42009-08-14 18:33:38 -07001064 */
1065 public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
1066 BluetoothServerSocket socket = new BluetoothServerSocket(
1067 BluetoothSocket.TYPE_RFCOMM, false, false, port);
Nick Pelly24bb9b82009-10-02 20:34:18 -07001068 int errno = socket.mSocket.bindListen();
1069 if (errno != 0) {
Nick Pellybd022f42009-08-14 18:33:38 -07001070 try {
1071 socket.close();
Nick Pelly24bb9b82009-10-02 20:34:18 -07001072 } catch (IOException e) {}
1073 socket.mSocket.throwErrnoNative(errno);
Nick Pellybd022f42009-08-14 18:33:38 -07001074 }
1075 return socket;
1076 }
1077
Mathias Jeppssone3b9dc102011-03-21 15:06:52 +01001078 /**
1079 * Construct an encrypted, RFCOMM server socket.
1080 * Call #accept to retrieve connections to this socket.
1081 * @return An RFCOMM BluetoothServerSocket
1082 * @throws IOException On error, for example Bluetooth not available, or
1083 * insufficient permissions.
1084 * @hide
1085 */
1086 public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
1087 throws IOException {
1088 BluetoothServerSocket socket = new BluetoothServerSocket(
1089 BluetoothSocket.TYPE_RFCOMM, false, true, port);
1090 int errno = socket.mSocket.bindListen();
1091 if (errno != 0) {
1092 try {
1093 socket.close();
1094 } catch (IOException e) {}
1095 socket.mSocket.throwErrnoNative(errno);
1096 }
1097 return socket;
1098 }
1099
Nick Pellybd022f42009-08-14 18:33:38 -07001100 /**
1101 * Construct a SCO server socket.
1102 * Call #accept to retrieve connections to this socket.
1103 * @return A SCO BluetoothServerSocket
1104 * @throws IOException On error, for example Bluetooth not available, or
1105 * insufficient permissions.
Nick Pelly45e27042009-08-19 11:00:00 -07001106 * @hide
Nick Pellybd022f42009-08-14 18:33:38 -07001107 */
1108 public static BluetoothServerSocket listenUsingScoOn() throws IOException {
1109 BluetoothServerSocket socket = new BluetoothServerSocket(
1110 BluetoothSocket.TYPE_SCO, false, false, -1);
Nick Pelly24bb9b82009-10-02 20:34:18 -07001111 int errno = socket.mSocket.bindListen();
1112 if (errno != 0) {
Nick Pellybd022f42009-08-14 18:33:38 -07001113 try {
1114 socket.close();
Nick Pelly24bb9b82009-10-02 20:34:18 -07001115 } catch (IOException e) {}
1116 socket.mSocket.throwErrnoNative(errno);
Nick Pellybd022f42009-08-14 18:33:38 -07001117 }
1118 return socket;
1119 }
1120
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -07001121 /**
1122 * Read the local Out of Band Pairing Data
1123 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1124 *
1125 * @return Pair<byte[], byte[]> of Hash and Randomizer
1126 *
1127 * @hide
1128 */
1129 public Pair<byte[], byte[]> readOutOfBandData() {
1130 if (getState() != STATE_ON) return null;
1131 try {
Jake Hambyf51eada2010-09-21 13:39:53 -07001132 byte[] hash;
1133 byte[] randomizer;
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -07001134
1135 byte[] ret = mService.readOutOfBandData();
1136
1137 if (ret == null || ret.length != 32) return null;
1138
1139 hash = Arrays.copyOfRange(ret, 0, 16);
1140 randomizer = Arrays.copyOfRange(ret, 16, 32);
1141
1142 if (DBG) {
1143 Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
1144 ":" + Arrays.toString(randomizer));
1145 }
1146 return new Pair<byte[], byte[]>(hash, randomizer);
1147
1148 } catch (RemoteException e) {Log.e(TAG, "", e);}
1149 return null;
1150 }
1151
Scott Main299ae672011-01-19 21:13:18 -08001152 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -07001153 * Get the profile proxy object associated with the profile.
1154 *
Scott Main2d68a6b2011-09-26 22:59:38 -07001155 * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
Scott Main299ae672011-01-19 21:13:18 -08001156 * {@link BluetoothProfile#A2DP}. Clients must implements
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -07001157 * {@link BluetoothProfile.ServiceListener} to get notified of
1158 * the connection status and to get the proxy object.
1159 *
1160 * @param context Context of the application
1161 * @param listener The service Listener for connection callbacks.
Scott Main2d68a6b2011-09-26 22:59:38 -07001162 * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH},
1163 * {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -07001164 * @return true on success, false on error
1165 */
1166 public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
1167 int profile) {
1168 if (context == null || listener == null) return false;
1169
1170 if (profile == BluetoothProfile.HEADSET) {
1171 BluetoothHeadset headset = new BluetoothHeadset(context, listener);
1172 return true;
1173 } else if (profile == BluetoothProfile.A2DP) {
1174 BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
1175 return true;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -08001176 } else if (profile == BluetoothProfile.INPUT_DEVICE) {
1177 BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
1178 return true;
Jaikumar Ganesh74ef1192011-02-23 10:22:15 -08001179 } else if (profile == BluetoothProfile.PAN) {
1180 BluetoothPan pan = new BluetoothPan(context, listener);
1181 return true;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -07001182 } else if (profile == BluetoothProfile.HEALTH) {
1183 BluetoothHealth health = new BluetoothHealth(context, listener);
1184 return true;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -07001185 } else {
1186 return false;
1187 }
1188 }
1189
1190 /**
1191 * Close the connection of the profile proxy to the Service.
1192 *
1193 * <p> Clients should call this when they are no longer using
1194 * the proxy obtained from {@link #getProfileProxy}.
Scott Main2d68a6b2011-09-26 22:59:38 -07001195 * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -07001196 * {@link BluetoothProfile#A2DP}
1197 *
1198 * @param profile
1199 * @param proxy Profile proxy object
1200 */
1201 public void closeProfileProxy(int profile, BluetoothProfile proxy) {
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -08001202 if (proxy == null) return;
1203
1204 switch (profile) {
1205 case BluetoothProfile.HEADSET:
1206 BluetoothHeadset headset = (BluetoothHeadset)proxy;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -07001207 headset.close();
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -08001208 break;
1209 case BluetoothProfile.A2DP:
1210 BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
1211 a2dp.close();
1212 break;
1213 case BluetoothProfile.INPUT_DEVICE:
1214 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
1215 iDev.close();
1216 break;
1217 case BluetoothProfile.PAN:
1218 BluetoothPan pan = (BluetoothPan)proxy;
1219 pan.close();
1220 break;
1221 case BluetoothProfile.HEALTH:
1222 BluetoothHealth health = (BluetoothHealth)proxy;
1223 health.close();
1224 break;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -07001225 }
1226 }
1227
Jaikumar Ganeshef2cb7c2011-07-21 18:13:38 -07001228 /**
1229 * Enable control of the Bluetooth Adapter for a single application.
1230 *
1231 * <p>Some applications need to use Bluetooth for short periods of time to
1232 * transfer data but don't want all the associated implications like
1233 * automatic connection to headsets etc.
1234 *
1235 * <p> Multiple applications can call this. This is reference counted and
1236 * Bluetooth disabled only when no one else is using it. There will be no UI
1237 * shown to the user while bluetooth is being enabled. Any user action will
1238 * override this call. For example, if user wants Bluetooth on and the last
1239 * user of this API wanted to disable Bluetooth, Bluetooth will not be
1240 * turned off.
1241 *
1242 * <p> This API is only meant to be used by internal applications. Third
1243 * party applications but use {@link #enable} and {@link #disable} APIs.
1244 *
1245 * <p> If this API returns true, it means the callback will be called.
1246 * The callback will be called with the current state of Bluetooth.
1247 * If the state is not what was requested, an internal error would be the
Jaikumar Ganeshf5fb6c82011-08-03 14:17:22 -07001248 * reason. If Bluetooth is already on and if this function is called to turn
1249 * it on, the api will return true and a callback will be called.
1250 *
1251 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
Jaikumar Ganeshef2cb7c2011-07-21 18:13:38 -07001252 *
1253 * @param on True for on, false for off.
1254 * @param callback The callback to notify changes to the state.
1255 * @hide
1256 */
1257 public boolean changeApplicationBluetoothState(boolean on,
1258 BluetoothStateChangeCallback callback) {
1259 if (callback == null) return false;
1260
1261 try {
1262 return mService.changeApplicationBluetoothState(on, new
1263 StateChangeCallbackWrapper(callback), new Binder());
1264 } catch (RemoteException e) {
1265 Log.e(TAG, "changeBluetoothState", e);
1266 }
1267 return false;
1268 }
1269
1270 /**
1271 * @hide
1272 */
1273 public interface BluetoothStateChangeCallback {
1274 public void onBluetoothStateChange(boolean on);
1275 }
1276
1277 /**
1278 * @hide
1279 */
1280 public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
1281 private BluetoothStateChangeCallback mCallback;
1282
1283 StateChangeCallbackWrapper(BluetoothStateChangeCallback
1284 callback) {
1285 mCallback = callback;
1286 }
1287
1288 @Override
1289 public void onBluetoothStateChange(boolean on) {
1290 mCallback.onBluetoothStateChange(on);
1291 }
1292 }
1293
Nick Pellybd022f42009-08-14 18:33:38 -07001294 private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
1295 Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
1296 for (int i = 0; i < addresses.length; i++) {
1297 devices.add(getRemoteDevice(addresses[i]));
1298 }
1299 return Collections.unmodifiableSet(devices);
1300 }
Nick Pelly005b2282009-09-10 10:21:56 -07001301
1302 /**
Nick Pelly75596b42011-12-07 15:03:55 -08001303 * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
Nick Pelly55e66f12009-09-18 11:37:06 -07001304 * <p>Alphabetic characters must be uppercase to be valid.
Nick Pelly005b2282009-09-10 10:21:56 -07001305 *
1306 * @param address Bluetooth address as string
1307 * @return true if the address is valid, false otherwise
1308 */
1309 public static boolean checkBluetoothAddress(String address) {
1310 if (address == null || address.length() != ADDRESS_LENGTH) {
1311 return false;
1312 }
1313 for (int i = 0; i < ADDRESS_LENGTH; i++) {
1314 char c = address.charAt(i);
1315 switch (i % 3) {
1316 case 0:
1317 case 1:
Nick Pelly55e66f12009-09-18 11:37:06 -07001318 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
1319 // hex character, OK
1320 break;
Nick Pelly005b2282009-09-10 10:21:56 -07001321 }
1322 return false;
1323 case 2:
1324 if (c == ':') {
1325 break; // OK
1326 }
1327 return false;
1328 }
1329 }
1330 return true;
1331 }
Nick Pellybd022f42009-08-14 18:33:38 -07001332}