BluetoothAdapter.java revision 0d376053747615ac7c4b45ab7810329ffbdf80d1
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.content.Context;
22import android.os.Binder;
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;
30import java.io.IOException;
31import java.lang.ref.WeakReference;
32import java.util.ArrayList;
33import java.util.Arrays;
34import java.util.Collections;
35import java.util.HashSet;
36import java.util.HashMap;
37import java.util.LinkedList;
38import java.util.Locale;
39import java.util.Map;
40import java.util.Random;
41import java.util.Set;
42import java.util.UUID;
43
44/**
45 * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
46 * lets you perform fundamental Bluetooth tasks, such as initiate
47 * device discovery, query a list of bonded (paired) devices,
48 * instantiate a {@link BluetoothDevice} using a known MAC address, and create
49 * a {@link BluetoothServerSocket} to listen for connection requests from other
50 * devices, and start a scan for Bluetooth LE devices.
51 *
52 * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
53 * adapter, when running on JELLY_BEAN_MR1 and below, call the
54 * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and
55 * higher, retrieve it through
56 * {@link android.content.Context#getSystemService} with
57 * {@link android.content.Context#BLUETOOTH_SERVICE}.
58 * Fundamentally, this is your starting point for all
59 * Bluetooth actions. Once you have the local adapter, you can get a set of
60 * {@link BluetoothDevice} objects representing all paired devices with
61 * {@link #getBondedDevices()}; start device discovery with
62 * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
63 * listen for incoming connection requests with
64 * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for
65 * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
66 *
67 * <p class="note"><strong>Note:</strong>
68 * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
69 * permission and some also require the
70 * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
71 *
72 * <div class="special reference">
73 * <h3>Developer Guides</h3>
74 * <p>For more information about using Bluetooth, read the
75 * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p>
76 * </div>
77 *
78 * {@see BluetoothDevice}
79 * {@see BluetoothServerSocket}
80 */
81public final class BluetoothAdapter {
82    private static final String TAG = "BluetoothAdapter";
83    private static final boolean DBG = true;
84    private static final boolean VDBG = false;
85
86    /**
87     * Sentinel error value for this class. Guaranteed to not equal any other
88     * integer constant in this class. Provided as a convenience for functions
89     * that require a sentinel error value, for example:
90     * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
91     * BluetoothAdapter.ERROR)</code>
92     */
93    public static final int ERROR = Integer.MIN_VALUE;
94
95    /**
96     * Broadcast Action: The state of the local Bluetooth adapter has been
97     * changed.
98     * <p>For example, Bluetooth has been turned on or off.
99     * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
100     * #EXTRA_PREVIOUS_STATE} containing the new and old states
101     * respectively.
102     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
103     */
104    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
105    public static final String ACTION_STATE_CHANGED =
106            "android.bluetooth.adapter.action.STATE_CHANGED";
107
108    /**
109     * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
110     * intents to request the current power state. Possible values are:
111     * {@link #STATE_OFF},
112     * {@link #STATE_TURNING_ON},
113     * {@link #STATE_ON},
114     * {@link #STATE_TURNING_OFF},
115     */
116    public static final String EXTRA_STATE =
117            "android.bluetooth.adapter.extra.STATE";
118    /**
119     * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
120     * intents to request the previous power state. Possible values are:
121     * {@link #STATE_OFF},
122     * {@link #STATE_TURNING_ON},
123     * {@link #STATE_ON},
124     * {@link #STATE_TURNING_OFF},
125     */
126    public static final String EXTRA_PREVIOUS_STATE =
127            "android.bluetooth.adapter.extra.PREVIOUS_STATE";
128
129    /**
130     * Indicates the local Bluetooth adapter is off.
131     */
132    public static final int STATE_OFF = 10;
133    /**
134     * Indicates the local Bluetooth adapter is turning on. However local
135     * clients should wait for {@link #STATE_ON} before attempting to
136     * use the adapter.
137     */
138    public static final int STATE_TURNING_ON = 11;
139    /**
140     * Indicates the local Bluetooth adapter is on, and ready for use.
141     */
142    public static final int STATE_ON = 12;
143    /**
144     * Indicates the local Bluetooth adapter is turning off. Local clients
145     * should immediately attempt graceful disconnection of any remote links.
146     */
147    public static final int STATE_TURNING_OFF = 13;
148
149    /**
150     * Activity Action: Show a system activity that requests discoverable mode.
151     * This activity will also request the user to turn on Bluetooth if it
152     * is not currently enabled.
153     * <p>Discoverable mode is equivalent to {@link
154     * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see
155     * this Bluetooth adapter when they perform a discovery.
156     * <p>For privacy, Android is not discoverable by default.
157     * <p>The sender of this Intent can optionally use extra field {@link
158     * #EXTRA_DISCOVERABLE_DURATION} to request the duration of
159     * discoverability. Currently the default duration is 120 seconds, and
160     * maximum duration is capped at 300 seconds for each request.
161     * <p>Notification of the result of this activity is posted using the
162     * {@link android.app.Activity#onActivityResult} callback. The
163     * <code>resultCode</code>
164     * will be the duration (in seconds) of discoverability or
165     * {@link android.app.Activity#RESULT_CANCELED} if the user rejected
166     * discoverability or an error has occurred.
167     * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
168     * for global notification whenever the scan mode changes. For example, an
169     * application can be notified when the device has ended discoverability.
170     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
171     */
172    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
173    public static final String ACTION_REQUEST_DISCOVERABLE =
174            "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
175
176    /**
177     * Used as an optional int extra field in {@link
178     * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration
179     * for discoverability in seconds. The current default is 120 seconds, and
180     * requests over 300 seconds will be capped. These values could change.
181     */
182    public static final String EXTRA_DISCOVERABLE_DURATION =
183            "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
184
185    /**
186     * Activity Action: Show a system activity that allows the user to turn on
187     * Bluetooth.
188     * <p>This system activity will return once Bluetooth has completed turning
189     * on, or the user has decided not to turn Bluetooth on.
190     * <p>Notification of the result of this activity is posted using the
191     * {@link android.app.Activity#onActivityResult} callback. The
192     * <code>resultCode</code>
193     * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
194     * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
195     * has rejected the request or an error has occurred.
196     * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
197     * for global notification whenever Bluetooth is turned on or off.
198     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
199     */
200    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
201    public static final String ACTION_REQUEST_ENABLE =
202            "android.bluetooth.adapter.action.REQUEST_ENABLE";
203
204    /**
205     * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
206     * has changed.
207     * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
208     * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
209     * respectively.
210     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
211     */
212    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
213    public static final String ACTION_SCAN_MODE_CHANGED =
214            "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
215
216    /**
217     * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
218     * intents to request the current scan mode. Possible values are:
219     * {@link #SCAN_MODE_NONE},
220     * {@link #SCAN_MODE_CONNECTABLE},
221     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
222     */
223    public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
224    /**
225     * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
226     * intents to request the previous scan mode. Possible values are:
227     * {@link #SCAN_MODE_NONE},
228     * {@link #SCAN_MODE_CONNECTABLE},
229     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
230     */
231    public static final String EXTRA_PREVIOUS_SCAN_MODE =
232            "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
233
234    /**
235     * Indicates that both inquiry scan and page scan are disabled on the local
236     * Bluetooth adapter. Therefore this device is neither discoverable
237     * nor connectable from remote Bluetooth devices.
238     */
239    public static final int SCAN_MODE_NONE = 20;
240    /**
241     * Indicates that inquiry scan is disabled, but page scan is enabled on the
242     * local Bluetooth adapter. Therefore this device is not discoverable from
243     * remote Bluetooth devices, but is connectable from remote devices that
244     * have previously discovered this device.
245     */
246    public static final int SCAN_MODE_CONNECTABLE = 21;
247    /**
248     * Indicates that both inquiry scan and page scan are enabled on the local
249     * Bluetooth adapter. Therefore this device is both discoverable and
250     * connectable from remote Bluetooth devices.
251     */
252    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
253
254
255    /**
256     * Broadcast Action: The local Bluetooth adapter has started the remote
257     * device discovery process.
258     * <p>This usually involves an inquiry scan of about 12 seconds, followed
259     * by a page scan of each new device to retrieve its Bluetooth name.
260     * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
261     * remote Bluetooth devices are found.
262     * <p>Device discovery is a heavyweight procedure. New connections to
263     * remote Bluetooth devices should not be attempted while discovery is in
264     * progress, and existing connections will experience limited bandwidth
265     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
266     * discovery.
267     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
268     */
269    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
270    public static final String ACTION_DISCOVERY_STARTED =
271            "android.bluetooth.adapter.action.DISCOVERY_STARTED";
272    /**
273     * Broadcast Action: The local Bluetooth adapter has finished the device
274     * discovery process.
275     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
276     */
277    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
278    public static final String ACTION_DISCOVERY_FINISHED =
279            "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
280
281    /**
282     * Broadcast Action: The local Bluetooth adapter has changed its friendly
283     * Bluetooth name.
284     * <p>This name is visible to remote Bluetooth devices.
285     * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
286     * the name.
287     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
288     */
289    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
290    public static final String ACTION_LOCAL_NAME_CHANGED =
291            "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
292    /**
293     * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
294     * intents to request the local Bluetooth name.
295     */
296    public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
297
298    /**
299     * Intent used to broadcast the change in connection state of the local
300     * Bluetooth adapter to a profile of the remote device. When the adapter is
301     * not connected to any profiles of any remote devices and it attempts a
302     * connection to a profile this intent will sent. Once connected, this intent
303     * will not be sent for any more connection attempts to any profiles of any
304     * remote device. When the adapter disconnects from the last profile its
305     * connected to of any remote device, this intent will be sent.
306     *
307     * <p> This intent is useful for applications that are only concerned about
308     * whether the local adapter is connected to any profile of any device and
309     * are not really concerned about which profile. For example, an application
310     * which displays an icon to display whether Bluetooth is connected or not
311     * can use this intent.
312     *
313     * <p>This intent will have 3 extras:
314     * {@link #EXTRA_CONNECTION_STATE} - The current connection state.
315     * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state.
316     * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
317     *
318     * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE}
319     * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
320     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
321     *
322     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
323     */
324    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
325    public static final String ACTION_CONNECTION_STATE_CHANGED =
326        "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
327
328    /**
329     * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
330     *
331     * This extra represents the current connection state.
332     */
333    public static final String EXTRA_CONNECTION_STATE =
334        "android.bluetooth.adapter.extra.CONNECTION_STATE";
335
336    /**
337     * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
338     *
339     * This extra represents the previous connection state.
340     */
341    public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
342          "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
343
344    /** The profile is in disconnected state */
345    public static final int STATE_DISCONNECTED  = 0;
346    /** The profile is in connecting state */
347    public static final int STATE_CONNECTING    = 1;
348    /** The profile is in connected state */
349    public static final int STATE_CONNECTED     = 2;
350    /** The profile is in disconnecting state */
351    public static final int STATE_DISCONNECTING = 3;
352
353    /** @hide */
354    public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
355
356    private static final int ADDRESS_LENGTH = 17;
357
358    /**
359     * Lazily initialized singleton. Guaranteed final after first object
360     * constructed.
361     */
362    private static BluetoothAdapter sAdapter;
363
364    private final IBluetoothManager mManagerService;
365    private IBluetooth mService;
366
367    private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients;
368
369    /**
370     * Get a handle to the default local Bluetooth adapter.
371     * <p>Currently Android only supports one Bluetooth adapter, but the API
372     * could be extended to support more. This will always return the default
373     * adapter.
374     * @return the default local adapter, or null if Bluetooth is not supported
375     *         on this hardware platform
376     */
377    public static synchronized BluetoothAdapter getDefaultAdapter() {
378        if (sAdapter == null) {
379            IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
380            if (b != null) {
381                IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
382                sAdapter = new BluetoothAdapter(managerService);
383            } else {
384                Log.e(TAG, "Bluetooth binder is null");
385            }
386        }
387        return sAdapter;
388    }
389
390    /**
391     * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
392     */
393    BluetoothAdapter(IBluetoothManager managerService) {
394
395        if (managerService == null) {
396            throw new IllegalArgumentException("bluetooth manager service is null");
397        }
398        try {
399            mService = managerService.registerAdapter(mManagerCallback);
400        } catch (RemoteException e) {Log.e(TAG, "", e);}
401        mManagerService = managerService;
402        mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
403    }
404
405    /**
406     * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
407     * address.
408     * <p>Valid Bluetooth hardware addresses must be upper case, in a format
409     * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
410     * available to validate a Bluetooth address.
411     * <p>A {@link BluetoothDevice} will always be returned for a valid
412     * hardware address, even if this adapter has never seen that device.
413     *
414     * @param address valid Bluetooth MAC address
415     * @throws IllegalArgumentException if address is invalid
416     */
417    public BluetoothDevice getRemoteDevice(String address) {
418        return new BluetoothDevice(address);
419    }
420
421    /**
422     * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
423     * address.
424     * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method
425     * expects the address in network byte order (MSB first).
426     * <p>A {@link BluetoothDevice} will always be returned for a valid
427     * hardware address, even if this adapter has never seen that device.
428     *
429     * @param address Bluetooth MAC address (6 bytes)
430     * @throws IllegalArgumentException if address is invalid
431     */
432    public BluetoothDevice getRemoteDevice(byte[] address) {
433        if (address == null || address.length != 6) {
434            throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
435        }
436        return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
437                address[0], address[1], address[2], address[3], address[4], address[5]));
438    }
439
440    /**
441     * Return true if Bluetooth is currently enabled and ready for use.
442     * <p>Equivalent to:
443     * <code>getBluetoothState() == STATE_ON</code>
444     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
445     *
446     * @return true if the local adapter is turned on
447     */
448    public boolean isEnabled() {
449
450        try {
451            synchronized(mManagerCallback) {
452                if (mService != null) return mService.isEnabled();
453            }
454        } catch (RemoteException e) {Log.e(TAG, "", e);}
455        return false;
456    }
457
458    /**
459     * Get the current state of the local Bluetooth adapter.
460     * <p>Possible return values are
461     * {@link #STATE_OFF},
462     * {@link #STATE_TURNING_ON},
463     * {@link #STATE_ON},
464     * {@link #STATE_TURNING_OFF}.
465     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
466     *
467     * @return current state of Bluetooth adapter
468     */
469    public int getState() {
470        try {
471            synchronized(mManagerCallback) {
472                if (mService != null)
473                {
474                    int state=  mService.getState();
475                    if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
476                    return state;
477                }
478                // TODO(BT) there might be a small gap during STATE_TURNING_ON that
479                //          mService is null, handle that case
480            }
481        } catch (RemoteException e) {Log.e(TAG, "", e);}
482        if (DBG) Log.d(TAG, "" + hashCode() + ": getState() :  mService = null. Returning STATE_OFF");
483        return STATE_OFF;
484    }
485
486    /**
487     * Turn on the local Bluetooth adapter&mdash;do not use without explicit
488     * user action to turn on Bluetooth.
489     * <p>This powers on the underlying Bluetooth hardware, and starts all
490     * Bluetooth system services.
491     * <p class="caution"><strong>Bluetooth should never be enabled without
492     * direct user consent</strong>. If you want to turn on Bluetooth in order
493     * to create a wireless connection, you should use the {@link
494     * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
495     * user permission to turn on Bluetooth. The {@link #enable()} method is
496     * provided only for applications that include a user interface for changing
497     * system settings, such as a "power manager" app.</p>
498     * <p>This is an asynchronous call: it will return immediately, and
499     * clients should listen for {@link #ACTION_STATE_CHANGED}
500     * to be notified of subsequent adapter state changes. If this call returns
501     * true, then the adapter state will immediately transition from {@link
502     * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
503     * later transition to either {@link #STATE_OFF} or {@link
504     * #STATE_ON}. If this call returns false then there was an
505     * immediate problem that will prevent the adapter from being turned on -
506     * such as Airplane mode, or the adapter is already turned on.
507     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
508     * permission
509     *
510     * @return true to indicate adapter startup has begun, or false on
511     *         immediate error
512     */
513    public boolean enable() {
514        if (isEnabled() == true){
515            if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
516            return true;
517        }
518        try {
519            return mManagerService.enable();
520        } catch (RemoteException e) {Log.e(TAG, "", e);}
521        return false;
522    }
523
524    /**
525     * Turn off the local Bluetooth adapter&mdash;do not use without explicit
526     * user action to turn off Bluetooth.
527     * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
528     * system services, and powers down the underlying Bluetooth hardware.
529     * <p class="caution"><strong>Bluetooth should never be disabled without
530     * direct user consent</strong>. The {@link #disable()} method is
531     * provided only for applications that include a user interface for changing
532     * system settings, such as a "power manager" app.</p>
533     * <p>This is an asynchronous call: it will return immediately, and
534     * clients should listen for {@link #ACTION_STATE_CHANGED}
535     * to be notified of subsequent adapter state changes. If this call returns
536     * true, then the adapter state will immediately transition from {@link
537     * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
538     * later transition to either {@link #STATE_OFF} or {@link
539     * #STATE_ON}. If this call returns false then there was an
540     * immediate problem that will prevent the adapter from being turned off -
541     * such as the adapter already being turned off.
542     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
543     * permission
544     *
545     * @return true to indicate adapter shutdown has begun, or false on
546     *         immediate error
547     */
548    public boolean disable() {
549        try {
550            return mManagerService.disable(true);
551        } catch (RemoteException e) {Log.e(TAG, "", e);}
552        return false;
553    }
554
555    /**
556     * Turn off the local Bluetooth adapter and don't persist the setting.
557     *
558     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
559     * permission
560     *
561     * @return true to indicate adapter shutdown has begun, or false on
562     *         immediate error
563     * @hide
564     */
565    public boolean disable(boolean persist) {
566
567        try {
568            return mManagerService.disable(persist);
569        } catch (RemoteException e) {Log.e(TAG, "", e);}
570        return false;
571    }
572
573    /**
574     * Returns the hardware address of the local Bluetooth adapter.
575     * <p>For example, "00:11:22:AA:BB:CC".
576     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
577     *
578     * @return Bluetooth hardware address as string
579     */
580    public String getAddress() {
581        try {
582            return mManagerService.getAddress();
583        } catch (RemoteException e) {Log.e(TAG, "", e);}
584        return null;
585    }
586
587    /**
588     * Get the friendly Bluetooth name of the local Bluetooth adapter.
589     * <p>This name is visible to remote Bluetooth devices.
590     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
591     *
592     * @return the Bluetooth name, or null on error
593     */
594    public String getName() {
595        try {
596            return mManagerService.getName();
597        } catch (RemoteException e) {Log.e(TAG, "", e);}
598        return null;
599    }
600
601    /**
602     * enable or disable Bluetooth HCI snoop log.
603     *
604     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
605     * permission
606     *
607     * @return true to indicate configure HCI log successfully, or false on
608     *         immediate error
609     * @hide
610     */
611    public boolean configHciSnoopLog(boolean enable) {
612        try {
613            synchronized(mManagerCallback) {
614                if (mService != null) return mService.configHciSnoopLog(enable);
615            }
616        } catch (RemoteException e) {Log.e(TAG, "", e);}
617        return false;
618    }
619
620    /**
621     * Get the UUIDs supported by the local Bluetooth adapter.
622     *
623     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
624     *
625     * @return the UUIDs supported by the local Bluetooth Adapter.
626     * @hide
627     */
628    public ParcelUuid[] getUuids() {
629        if (getState() != STATE_ON) return null;
630        try {
631            synchronized(mManagerCallback) {
632                if (mService != null) return mService.getUuids();
633            }
634        } catch (RemoteException e) {Log.e(TAG, "", e);}
635        return null;
636    }
637
638    /**
639     * Set the friendly Bluetooth name of the local Bluetooth adapter.
640     * <p>This name is visible to remote Bluetooth devices.
641     * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
642     * encoding, although many remote devices can only display the first
643     * 40 characters, and some may be limited to just 20.
644     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
645     * will return false. After turning on Bluetooth,
646     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
647     * to get the updated value.
648     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
649     *
650     * @param name a valid Bluetooth name
651     * @return     true if the name was set, false otherwise
652     */
653    public boolean setName(String name) {
654        if (getState() != STATE_ON) return false;
655        try {
656            synchronized(mManagerCallback) {
657                if (mService != null) return mService.setName(name);
658            }
659        } catch (RemoteException e) {Log.e(TAG, "", e);}
660        return false;
661    }
662
663    /**
664     * Get the current Bluetooth scan mode of the local Bluetooth adapter.
665     * <p>The Bluetooth scan mode determines if the local adapter is
666     * connectable and/or discoverable from remote Bluetooth devices.
667     * <p>Possible values are:
668     * {@link #SCAN_MODE_NONE},
669     * {@link #SCAN_MODE_CONNECTABLE},
670     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
671     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
672     * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
673     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
674     * to get the updated value.
675     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
676     *
677     * @return scan mode
678     */
679    public int getScanMode() {
680        if (getState() != STATE_ON) return SCAN_MODE_NONE;
681        try {
682            synchronized(mManagerCallback) {
683                if (mService != null) return mService.getScanMode();
684            }
685        } catch (RemoteException e) {Log.e(TAG, "", e);}
686        return SCAN_MODE_NONE;
687    }
688
689    /**
690     * Set the Bluetooth scan mode of the local Bluetooth adapter.
691     * <p>The Bluetooth scan mode determines if the local adapter is
692     * connectable and/or discoverable from remote Bluetooth devices.
693     * <p>For privacy reasons, discoverable mode is automatically turned off
694     * after <code>duration</code> seconds. For example, 120 seconds should be
695     * enough for a remote device to initiate and complete its discovery
696     * process.
697     * <p>Valid scan mode values are:
698     * {@link #SCAN_MODE_NONE},
699     * {@link #SCAN_MODE_CONNECTABLE},
700     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
701     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
702     * will return false. After turning on Bluetooth,
703     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
704     * to get the updated value.
705     * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
706     * <p>Applications cannot set the scan mode. They should use
707     * <code>startActivityForResult(
708     * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
709     * </code>instead.
710     *
711     * @param mode valid scan mode
712     * @param duration time in seconds to apply scan mode, only used for
713     *                 {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
714     * @return     true if the scan mode was set, false otherwise
715     * @hide
716     */
717    public boolean setScanMode(int mode, int duration) {
718        if (getState() != STATE_ON) return false;
719        try {
720            synchronized(mManagerCallback) {
721                if (mService != null) return mService.setScanMode(mode, duration);
722            }
723        } catch (RemoteException e) {Log.e(TAG, "", e);}
724        return false;
725    }
726
727    /** @hide */
728    public boolean setScanMode(int mode) {
729        if (getState() != STATE_ON) return false;
730        /* getDiscoverableTimeout() to use the latest from NV than use 0 */
731        return setScanMode(mode, getDiscoverableTimeout());
732    }
733
734    /** @hide */
735    public int getDiscoverableTimeout() {
736        if (getState() != STATE_ON) return -1;
737        try {
738            synchronized(mManagerCallback) {
739                if (mService != null) return mService.getDiscoverableTimeout();
740            }
741        } catch (RemoteException e) {Log.e(TAG, "", e);}
742        return -1;
743    }
744
745    /** @hide */
746    public void setDiscoverableTimeout(int timeout) {
747        if (getState() != STATE_ON) return;
748        try {
749            synchronized(mManagerCallback) {
750                if (mService != null) mService.setDiscoverableTimeout(timeout);
751            }
752        } catch (RemoteException e) {Log.e(TAG, "", e);}
753    }
754
755    /**
756     * Start the remote device discovery process.
757     * <p>The discovery process usually involves an inquiry scan of about 12
758     * seconds, followed by a page scan of each new device to retrieve its
759     * Bluetooth name.
760     * <p>This is an asynchronous call, it will return immediately. Register
761     * for {@link #ACTION_DISCOVERY_STARTED} and {@link
762     * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
763     * discovery starts and completes. Register for {@link
764     * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
765     * are found.
766     * <p>Device discovery is a heavyweight procedure. New connections to
767     * remote Bluetooth devices should not be attempted while discovery is in
768     * progress, and existing connections will experience limited bandwidth
769     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
770     * discovery. Discovery is not managed by the Activity,
771     * but is run as a system service, so an application should always call
772     * {@link BluetoothAdapter#cancelDiscovery()} even if it
773     * did not directly request a discovery, just to be sure.
774     * <p>Device discovery will only find remote devices that are currently
775     * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
776     * not discoverable by default, and need to be entered into a special mode.
777     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
778     * will return false. After turning on Bluetooth,
779     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
780     * to get the updated value.
781     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
782     *
783     * @return true on success, false on error
784     */
785    public boolean startDiscovery() {
786        if (getState() != STATE_ON) return false;
787        try {
788            synchronized(mManagerCallback) {
789                if (mService != null) return mService.startDiscovery();
790            }
791        } catch (RemoteException e) {Log.e(TAG, "", e);}
792        return false;
793    }
794
795    /**
796     * Cancel the current device discovery process.
797     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
798     * <p>Because discovery is a heavyweight procedure for the Bluetooth
799     * adapter, this method should always be called before attempting to connect
800     * to a remote device with {@link
801     * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
802     * the  Activity, but is run as a system service, so an application should
803     * always call cancel discovery even if it did not directly request a
804     * discovery, just to be sure.
805     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
806     * will return false. After turning on Bluetooth,
807     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
808     * to get the updated value.
809     *
810     * @return true on success, false on error
811     */
812    public boolean cancelDiscovery() {
813        if (getState() != STATE_ON) return false;
814        try {
815            synchronized(mManagerCallback) {
816                if (mService != null) return mService.cancelDiscovery();
817            }
818        } catch (RemoteException e) {Log.e(TAG, "", e);}
819        return false;
820    }
821
822    /**
823     * Return true if the local Bluetooth adapter is currently in the device
824     * discovery process.
825     * <p>Device discovery is a heavyweight procedure. New connections to
826     * remote Bluetooth devices should not be attempted while discovery is in
827     * progress, and existing connections will experience limited bandwidth
828     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
829     * discovery.
830     * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
831     * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
832     * starts or completes.
833     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
834     * will return false. After turning on Bluetooth,
835     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
836     * to get the updated value.
837     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
838     *
839     * @return true if discovering
840     */
841    public boolean isDiscovering() {
842        if (getState() != STATE_ON) return false;
843        try {
844            synchronized(mManagerCallback) {
845                if (mService != null ) return mService.isDiscovering();
846            }
847        } catch (RemoteException e) {Log.e(TAG, "", e);}
848        return false;
849    }
850
851    /**
852     * Return the set of {@link BluetoothDevice} objects that are bonded
853     * (paired) to the local adapter.
854     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
855     * will return an empty set. After turning on Bluetooth,
856     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
857     * to get the updated value.
858     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
859     *
860     * @return unmodifiable set of {@link BluetoothDevice}, or null on error
861     */
862    public Set<BluetoothDevice> getBondedDevices() {
863        if (getState() != STATE_ON) {
864            return toDeviceSet(new BluetoothDevice[0]);
865        }
866        try {
867            synchronized(mManagerCallback) {
868                if (mService != null) return toDeviceSet(mService.getBondedDevices());
869            }
870            return toDeviceSet(new BluetoothDevice[0]);
871        } catch (RemoteException e) {Log.e(TAG, "", e);}
872        return null;
873    }
874
875    /**
876     * Get the current connection state of the local Bluetooth adapter.
877     * This can be used to check whether the local Bluetooth adapter is connected
878     * to any profile of any other remote Bluetooth Device.
879     *
880     * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
881     * intent to get the connection state of the adapter.
882     *
883     * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED},
884     * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
885     *
886     * @hide
887     */
888    public int getConnectionState() {
889        if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
890        try {
891            synchronized(mManagerCallback) {
892                if (mService != null) return mService.getAdapterConnectionState();
893            }
894        } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
895        return BluetoothAdapter.STATE_DISCONNECTED;
896    }
897
898    /**
899     * Get the current connection state of a profile.
900     * This function can be used to check whether the local Bluetooth adapter
901     * is connected to any remote device for a specific profile.
902     * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
903     * {@link BluetoothProfile#A2DP}.
904     *
905     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
906     *
907     * <p> Return value can be one of
908     * {@link BluetoothProfile#STATE_DISCONNECTED},
909     * {@link BluetoothProfile#STATE_CONNECTING},
910     * {@link BluetoothProfile#STATE_CONNECTED},
911     * {@link BluetoothProfile#STATE_DISCONNECTING}
912     */
913    public int getProfileConnectionState(int profile) {
914        if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
915        try {
916            synchronized(mManagerCallback) {
917                if (mService != null) return mService.getProfileConnectionState(profile);
918            }
919        } catch (RemoteException e) {
920            Log.e(TAG, "getProfileConnectionState:", e);
921        }
922        return BluetoothProfile.STATE_DISCONNECTED;
923    }
924
925    /**
926     * Create a listening, L2CAP Bluetooth socket.
927     * <p>A remote device connecting to this socket will optionally be
928     * authenticated and communication on this socket will optionally be
929     * encrypted.
930     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
931     * connections from a listening {@link BluetoothServerSocket}.
932     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
933     * @param secure whether security and authentication are required
934     * @param fixedChannel whether we're looking for a PSM-based connection or a fixed channel
935     * @param channel L2CAP PSM or channel to use
936     * @return a listening L2CAP BluetoothServerSocket
937     * @throws IOException on error, for example Bluetooth not available, or
938     *                     insufficient permissions, or channel in use.
939     * @hide
940     */
941    public BluetoothServerSocket listenUsingL2CapOn(boolean secure, boolean fixedChannel,
942            int channel) throws IOException {
943        BluetoothServerSocket socket;
944
945        if (fixedChannel) {
946            channel |= BluetoothSocket.PORT_MASK_FIXED_CHAN;
947        }
948
949        socket = new BluetoothServerSocket(
950                BluetoothSocket.TYPE_L2CAP, secure, secure, channel);
951        int errno = socket.mSocket.bindListen();
952        if (errno != 0) {
953            //TODO(BT): Throw the same exception error code
954            // that the previous code was using.
955            //socket.mSocket.throwErrnoNative(errno);
956            throw new IOException("Error: " + errno);
957        }
958        return socket;
959    }
960
961    /**
962     * Create a listening, secure RFCOMM Bluetooth socket.
963     * <p>A remote device connecting to this socket will be authenticated and
964     * communication on this socket will be encrypted.
965     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
966     * connections from a listening {@link BluetoothServerSocket}.
967     * <p>Valid RFCOMM channels are in range 1 to 30.
968     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
969     * @param channel RFCOMM channel to listen on
970     * @return a listening RFCOMM BluetoothServerSocket
971     * @throws IOException on error, for example Bluetooth not available, or
972     *                     insufficient permissions, or channel in use.
973     * @hide
974     */
975    public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
976        BluetoothServerSocket socket = new BluetoothServerSocket(
977                BluetoothSocket.TYPE_RFCOMM, true, true, channel);
978        int errno = socket.mSocket.bindListen();
979        if (errno != 0) {
980            //TODO(BT): Throw the same exception error code
981            // that the previous code was using.
982            //socket.mSocket.throwErrnoNative(errno);
983            throw new IOException("Error: " + errno);
984        }
985        return socket;
986    }
987
988    /**
989     * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
990     * <p>A remote device connecting to this socket will be authenticated and
991     * communication on this socket will be encrypted.
992     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
993     * connections from a listening {@link BluetoothServerSocket}.
994     * <p>The system will assign an unused RFCOMM channel to listen on.
995     * <p>The system will also register a Service Discovery
996     * Protocol (SDP) record with the local SDP server containing the specified
997     * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
998     * can use the same UUID to query our SDP server and discover which channel
999     * to connect to. This SDP record will be removed when this socket is
1000     * closed, or if this application closes unexpectedly.
1001     * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1002     * connect to this socket from another device using the same {@link UUID}.
1003     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1004     * @param name service name for SDP record
1005     * @param uuid uuid for SDP record
1006     * @return a listening RFCOMM BluetoothServerSocket
1007     * @throws IOException on error, for example Bluetooth not available, or
1008     *                     insufficient permissions, or channel in use.
1009     */
1010    public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
1011            throws IOException {
1012        return createNewRfcommSocketAndRecord(name, uuid, true, true);
1013    }
1014
1015    /**
1016     * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
1017     * <p>The link key is not required to be authenticated, i.e the communication may be
1018     * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
1019     * the link will be encrypted, as encryption is mandartory.
1020     * For legacy devices (pre Bluetooth 2.1 devices) the link will not
1021     * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
1022     * encrypted and authenticated communication channel is desired.
1023     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1024     * connections from a listening {@link BluetoothServerSocket}.
1025     * <p>The system will assign an unused RFCOMM channel to listen on.
1026     * <p>The system will also register a Service Discovery
1027     * Protocol (SDP) record with the local SDP server containing the specified
1028     * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1029     * can use the same UUID to query our SDP server and discover which channel
1030     * to connect to. This SDP record will be removed when this socket is
1031     * closed, or if this application closes unexpectedly.
1032     * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1033     * connect to this socket from another device using the same {@link UUID}.
1034     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1035     * @param name service name for SDP record
1036     * @param uuid uuid for SDP record
1037     * @return a listening RFCOMM BluetoothServerSocket
1038     * @throws IOException on error, for example Bluetooth not available, or
1039     *                     insufficient permissions, or channel in use.
1040     */
1041    public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
1042            throws IOException {
1043        return createNewRfcommSocketAndRecord(name, uuid, false, false);
1044    }
1045
1046     /**
1047     * Create a listening, encrypted,
1048     * RFCOMM Bluetooth socket with Service Record.
1049     * <p>The link will be encrypted, but the link key is not required to be authenticated
1050     * i.e the communication is vulnerable to Man In the Middle attacks. Use
1051     * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
1052     * <p> Use this socket if authentication of link key is not possible.
1053     * For example, for Bluetooth 2.1 devices, if any of the devices does not have
1054     * an input and output capability or just has the ability to display a numeric key,
1055     * a secure socket connection is not possible and this socket can be used.
1056     * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
1057     * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory.
1058     * For more details, refer to the Security Model section 5.2 (vol 3) of
1059     * Bluetooth Core Specification version 2.1 + EDR.
1060     * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1061     * connections from a listening {@link BluetoothServerSocket}.
1062     * <p>The system will assign an unused RFCOMM channel to listen on.
1063     * <p>The system will also register a Service Discovery
1064     * Protocol (SDP) record with the local SDP server containing the specified
1065     * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1066     * can use the same UUID to query our SDP server and discover which channel
1067     * to connect to. This SDP record will be removed when this socket is
1068     * closed, or if this application closes unexpectedly.
1069     * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1070     * connect to this socket from another device using the same {@link UUID}.
1071     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1072     * @param name service name for SDP record
1073     * @param uuid uuid for SDP record
1074     * @return a listening RFCOMM BluetoothServerSocket
1075     * @throws IOException on error, for example Bluetooth not available, or
1076     *                     insufficient permissions, or channel in use.
1077     * @hide
1078     */
1079    public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
1080            String name, UUID uuid) throws IOException {
1081        return createNewRfcommSocketAndRecord(name, uuid, false, true);
1082    }
1083
1084
1085    private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
1086            boolean auth, boolean encrypt) throws IOException {
1087        BluetoothServerSocket socket;
1088        socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth,
1089                        encrypt, new ParcelUuid(uuid));
1090        socket.setServiceName(name);
1091        int errno = socket.mSocket.bindListen();
1092        if (errno != 0) {
1093            //TODO(BT): Throw the same exception error code
1094            // that the previous code was using.
1095            //socket.mSocket.throwErrnoNative(errno);
1096            throw new IOException("Error: " + errno);
1097        }
1098        return socket;
1099    }
1100
1101    /**
1102     * Construct an unencrypted, unauthenticated, RFCOMM server socket.
1103     * Call #accept to retrieve connections to this socket.
1104     * @return An RFCOMM BluetoothServerSocket
1105     * @throws IOException On error, for example Bluetooth not available, or
1106     *                     insufficient permissions.
1107     * @hide
1108     */
1109    public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
1110        BluetoothServerSocket socket = new BluetoothServerSocket(
1111                BluetoothSocket.TYPE_RFCOMM, false, false, port);
1112        int errno = socket.mSocket.bindListen();
1113        if (errno != 0) {
1114            //TODO(BT): Throw the same exception error code
1115            // that the previous code was using.
1116            //socket.mSocket.throwErrnoNative(errno);
1117            throw new IOException("Error: " + errno);
1118        }
1119        return socket;
1120    }
1121
1122     /**
1123     * Construct an encrypted, RFCOMM server socket.
1124     * Call #accept to retrieve connections to this socket.
1125     * @return An RFCOMM BluetoothServerSocket
1126     * @throws IOException On error, for example Bluetooth not available, or
1127     *                     insufficient permissions.
1128     * @hide
1129     */
1130    public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
1131            throws IOException {
1132        BluetoothServerSocket socket = new BluetoothServerSocket(
1133                BluetoothSocket.TYPE_RFCOMM, false, true, port);
1134        int errno = socket.mSocket.bindListen();
1135        if (errno < 0) {
1136            //TODO(BT): Throw the same exception error code
1137            // that the previous code was using.
1138            //socket.mSocket.throwErrnoNative(errno);
1139            throw new IOException("Error: " + errno);
1140        }
1141        return socket;
1142    }
1143
1144    /**
1145     * Construct a SCO server socket.
1146     * Call #accept to retrieve connections to this socket.
1147     * @return A SCO BluetoothServerSocket
1148     * @throws IOException On error, for example Bluetooth not available, or
1149     *                     insufficient permissions.
1150     * @hide
1151     */
1152    public static BluetoothServerSocket listenUsingScoOn() throws IOException {
1153        BluetoothServerSocket socket = new BluetoothServerSocket(
1154                BluetoothSocket.TYPE_SCO, false, false, -1);
1155        int errno = socket.mSocket.bindListen();
1156        if (errno < 0) {
1157            //TODO(BT): Throw the same exception error code
1158            // that the previous code was using.
1159            //socket.mSocket.throwErrnoNative(errno);
1160        }
1161        return socket;
1162    }
1163
1164    /**
1165     * Read the local Out of Band Pairing Data
1166     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1167     *
1168     * @return Pair<byte[], byte[]> of Hash and Randomizer
1169     *
1170     * @hide
1171     */
1172    public Pair<byte[], byte[]> readOutOfBandData() {
1173        if (getState() != STATE_ON) return null;
1174        //TODO(BT
1175        /*
1176        try {
1177            byte[] hash;
1178            byte[] randomizer;
1179
1180            byte[] ret = mService.readOutOfBandData();
1181
1182            if (ret  == null || ret.length != 32) return null;
1183
1184            hash = Arrays.copyOfRange(ret, 0, 16);
1185            randomizer = Arrays.copyOfRange(ret, 16, 32);
1186
1187            if (DBG) {
1188                Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
1189                  ":" + Arrays.toString(randomizer));
1190            }
1191            return new Pair<byte[], byte[]>(hash, randomizer);
1192
1193        } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1194        return null;
1195    }
1196
1197    /**
1198     * Get the profile proxy object associated with the profile.
1199     *
1200     * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
1201     * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
1202     * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
1203     * {@link BluetoothProfile.ServiceListener} to get notified of
1204     * the connection status and to get the proxy object.
1205     *
1206     * @param context Context of the application
1207     * @param listener The service Listener for connection callbacks.
1208     * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH},
1209     *                {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}.
1210     * @return true on success, false on error
1211     */
1212    public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
1213                                   int profile) {
1214        if (context == null || listener == null) return false;
1215
1216        if (profile == BluetoothProfile.HEADSET) {
1217            BluetoothHeadset headset = new BluetoothHeadset(context, listener);
1218            return true;
1219        } else if (profile == BluetoothProfile.A2DP) {
1220            BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
1221            return true;
1222        } else if (profile == BluetoothProfile.INPUT_DEVICE) {
1223            BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
1224            return true;
1225        } else if (profile == BluetoothProfile.PAN) {
1226            BluetoothPan pan = new BluetoothPan(context, listener);
1227            return true;
1228        } else if (profile == BluetoothProfile.HEALTH) {
1229            BluetoothHealth health = new BluetoothHealth(context, listener);
1230            return true;
1231        } else if (profile == BluetoothProfile.MAP) {
1232            BluetoothMap map = new BluetoothMap(context, listener);
1233            return true;
1234        } else {
1235            return false;
1236        }
1237    }
1238
1239    /**
1240     * Close the connection of the profile proxy to the Service.
1241     *
1242     * <p> Clients should call this when they are no longer using
1243     * the proxy obtained from {@link #getProfileProxy}.
1244     * Profile can be one of  {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
1245     * {@link BluetoothProfile#A2DP}
1246     *
1247     * @param profile
1248     * @param proxy Profile proxy object
1249     */
1250    public void closeProfileProxy(int profile, BluetoothProfile proxy) {
1251        if (proxy == null) return;
1252
1253        switch (profile) {
1254            case BluetoothProfile.HEADSET:
1255                BluetoothHeadset headset = (BluetoothHeadset)proxy;
1256                headset.close();
1257                break;
1258            case BluetoothProfile.A2DP:
1259                BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
1260                a2dp.close();
1261                break;
1262            case BluetoothProfile.INPUT_DEVICE:
1263                BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
1264                iDev.close();
1265                break;
1266            case BluetoothProfile.PAN:
1267                BluetoothPan pan = (BluetoothPan)proxy;
1268                pan.close();
1269                break;
1270            case BluetoothProfile.HEALTH:
1271                BluetoothHealth health = (BluetoothHealth)proxy;
1272                health.close();
1273                break;
1274           case BluetoothProfile.GATT:
1275                BluetoothGatt gatt = (BluetoothGatt)proxy;
1276                gatt.close();
1277                break;
1278            case BluetoothProfile.GATT_SERVER:
1279                BluetoothGattServer gattServer = (BluetoothGattServer)proxy;
1280                gattServer.close();
1281                break;
1282            case BluetoothProfile.MAP:
1283                BluetoothMap map = (BluetoothMap)proxy;
1284                map.close();
1285                break;
1286        }
1287    }
1288
1289    final private IBluetoothManagerCallback mManagerCallback =
1290        new IBluetoothManagerCallback.Stub() {
1291            public void onBluetoothServiceUp(IBluetooth bluetoothService) {
1292                if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
1293                synchronized (mManagerCallback) {
1294                    mService = bluetoothService;
1295                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
1296                        try {
1297                            if (cb != null) {
1298                                cb.onBluetoothServiceUp(bluetoothService);
1299                            } else {
1300                                Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
1301                            }
1302                        } catch (Exception e)  { Log.e(TAG,"",e);}
1303                    }
1304                }
1305            }
1306
1307            public void onBluetoothServiceDown() {
1308                if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
1309                synchronized (mManagerCallback) {
1310                    mService = null;
1311                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
1312                        try {
1313                            if (cb != null) {
1314                                cb.onBluetoothServiceDown();
1315                            } else {
1316                                Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
1317                            }
1318                        } catch (Exception e)  { Log.e(TAG,"",e);}
1319                    }
1320                }
1321            }
1322    };
1323
1324    /**
1325     * Enable the Bluetooth Adapter, but don't auto-connect devices
1326     * and don't persist state. Only for use by system applications.
1327     * @hide
1328     */
1329    public boolean enableNoAutoConnect() {
1330        if (isEnabled() == true){
1331            if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!");
1332            return true;
1333        }
1334        try {
1335            return mManagerService.enableNoAutoConnect();
1336        } catch (RemoteException e) {Log.e(TAG, "", e);}
1337        return false;
1338    }
1339
1340    /**
1341     * Enable control of the Bluetooth Adapter for a single application.
1342     *
1343     * <p>Some applications need to use Bluetooth for short periods of time to
1344     * transfer data but don't want all the associated implications like
1345     * automatic connection to headsets etc.
1346     *
1347     * <p> Multiple applications can call this. This is reference counted and
1348     * Bluetooth disabled only when no one else is using it. There will be no UI
1349     * shown to the user while bluetooth is being enabled. Any user action will
1350     * override this call. For example, if user wants Bluetooth on and the last
1351     * user of this API wanted to disable Bluetooth, Bluetooth will not be
1352     * turned off.
1353     *
1354     * <p> This API is only meant to be used by internal applications. Third
1355     * party applications but use {@link #enable} and {@link #disable} APIs.
1356     *
1357     * <p> If this API returns true, it means the callback will be called.
1358     * The callback will be called with the current state of Bluetooth.
1359     * If the state is not what was requested, an internal error would be the
1360     * reason. If Bluetooth is already on and if this function is called to turn
1361     * it on, the api will return true and a callback will be called.
1362     *
1363     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1364     *
1365     * @param on True for on, false for off.
1366     * @param callback The callback to notify changes to the state.
1367     * @hide
1368     */
1369    public boolean changeApplicationBluetoothState(boolean on,
1370                                                   BluetoothStateChangeCallback callback) {
1371        if (callback == null) return false;
1372
1373        //TODO(BT)
1374        /*
1375        try {
1376            return mService.changeApplicationBluetoothState(on, new
1377                    StateChangeCallbackWrapper(callback), new Binder());
1378        } catch (RemoteException e) {
1379            Log.e(TAG, "changeBluetoothState", e);
1380        }*/
1381        return false;
1382    }
1383
1384    /**
1385     * @hide
1386     */
1387    public interface BluetoothStateChangeCallback {
1388        public void onBluetoothStateChange(boolean on);
1389    }
1390
1391    /**
1392     * @hide
1393     */
1394    public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
1395        private BluetoothStateChangeCallback mCallback;
1396
1397        StateChangeCallbackWrapper(BluetoothStateChangeCallback
1398                callback) {
1399            mCallback = callback;
1400        }
1401
1402        @Override
1403        public void onBluetoothStateChange(boolean on) {
1404            mCallback.onBluetoothStateChange(on);
1405        }
1406    }
1407
1408    private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) {
1409        Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices));
1410        return Collections.unmodifiableSet(deviceSet);
1411    }
1412
1413    protected void finalize() throws Throwable {
1414        try {
1415            mManagerService.unregisterAdapter(mManagerCallback);
1416        } catch (RemoteException e) {
1417            Log.e(TAG, "", e);
1418        } finally {
1419            super.finalize();
1420        }
1421    }
1422
1423
1424    /**
1425     * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
1426     * <p>Alphabetic characters must be uppercase to be valid.
1427     *
1428     * @param address Bluetooth address as string
1429     * @return true if the address is valid, false otherwise
1430     */
1431    public static boolean checkBluetoothAddress(String address) {
1432        if (address == null || address.length() != ADDRESS_LENGTH) {
1433            return false;
1434        }
1435        for (int i = 0; i < ADDRESS_LENGTH; i++) {
1436            char c = address.charAt(i);
1437            switch (i % 3) {
1438            case 0:
1439            case 1:
1440                if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
1441                    // hex character, OK
1442                    break;
1443                }
1444                return false;
1445            case 2:
1446                if (c == ':') {
1447                    break;  // OK
1448                }
1449                return false;
1450            }
1451        }
1452        return true;
1453    }
1454
1455    /*package*/ IBluetoothManager getBluetoothManager() {
1456            return mManagerService;
1457    }
1458
1459    private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
1460
1461    /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
1462        synchronized (mManagerCallback) {
1463            if (cb == null) {
1464                Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
1465            } else if (!mProxyServiceStateCallbacks.contains(cb)) {
1466                mProxyServiceStateCallbacks.add(cb);
1467            }
1468        }
1469        return mService;
1470    }
1471
1472    /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
1473        synchronized (mManagerCallback) {
1474            mProxyServiceStateCallbacks.remove(cb);
1475        }
1476    }
1477
1478    /**
1479     * Callback interface used to deliver LE scan results.
1480     *
1481     * @see #startLeScan(LeScanCallback)
1482     * @see #startLeScan(UUID[], LeScanCallback)
1483     */
1484    public interface LeScanCallback {
1485        /**
1486         * Callback reporting an LE device found during a device scan initiated
1487         * by the {@link BluetoothAdapter#startLeScan} function.
1488         *
1489         * @param device Identifies the remote device
1490         * @param rssi The RSSI value for the remote device as reported by the
1491         *             Bluetooth hardware. 0 if no RSSI value is available.
1492         * @param scanRecord The content of the advertisement record offered by
1493         *                   the remote device.
1494         */
1495        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
1496    }
1497
1498    /**
1499     * Starts a scan for Bluetooth LE devices.
1500     *
1501     * <p>Results of the scan are reported using the
1502     * {@link LeScanCallback#onLeScan} callback.
1503     *
1504     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1505     *
1506     * @param callback the callback LE scan results are delivered
1507     * @return true, if the scan was started successfully
1508     */
1509    public boolean startLeScan(LeScanCallback callback) {
1510        return startLeScan(null, callback);
1511    }
1512
1513    /**
1514     * Starts a scan for Bluetooth LE devices, looking for devices that
1515     * advertise given services.
1516     *
1517     * <p>Devices which advertise all specified services are reported using the
1518     * {@link LeScanCallback#onLeScan} callback.
1519     *
1520     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1521     *
1522     * @param serviceUuids Array of services to look for
1523     * @param callback the callback LE scan results are delivered
1524     * @return true, if the scan was started successfully
1525     */
1526    public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
1527        if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
1528
1529        if (callback == null) {
1530            if (DBG) Log.e(TAG, "startLeScan: null callback");
1531            return false;
1532        }
1533
1534        synchronized(mLeScanClients) {
1535            if (mLeScanClients.containsKey(callback)) {
1536                if (DBG) Log.e(TAG, "LE Scan has already started");
1537                return false;
1538            }
1539
1540            try {
1541                IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
1542                if (iGatt == null) {
1543                    // BLE is not supported
1544                    return false;
1545                }
1546
1547                UUID uuid = UUID.randomUUID();
1548                GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
1549                iGatt.registerClient(new ParcelUuid(uuid), wrapper);
1550                if (wrapper.scanStarted()) {
1551                    mLeScanClients.put(callback, wrapper);
1552                    return true;
1553                }
1554            } catch (RemoteException e) {
1555                Log.e(TAG,"",e);
1556            }
1557        }
1558        return false;
1559    }
1560
1561    /**
1562     * Stops an ongoing Bluetooth LE device scan.
1563     *
1564     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1565     *
1566     * @param callback used to identify which scan to stop
1567     *        must be the same handle used to start the scan
1568     */
1569    public void stopLeScan(LeScanCallback callback) {
1570        if (DBG) Log.d(TAG, "stopLeScan()");
1571        GattCallbackWrapper wrapper;
1572        synchronized(mLeScanClients) {
1573            wrapper = mLeScanClients.remove(callback);
1574            if (wrapper == null) return;
1575        }
1576        wrapper.stopLeScan();
1577    }
1578
1579    /**
1580     * Bluetooth GATT interface callbacks
1581     */
1582    private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub {
1583        private static final int LE_CALLBACK_REG_TIMEOUT = 2000;
1584        private static final int LE_CALLBACK_REG_WAIT_COUNT = 5;
1585
1586        private final LeScanCallback mLeScanCb;
1587        // mLeHandle 0: not registered
1588        //           -1: scan stopped
1589        //           >0: registered and scan started
1590        private int mLeHandle;
1591        private final UUID[] mScanFilter;
1592        private WeakReference<BluetoothAdapter> mBluetoothAdapter;
1593
1594        public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter,
1595                                   LeScanCallback leScanCb, UUID[] uuid) {
1596            mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter);
1597            mLeScanCb = leScanCb;
1598            mScanFilter = uuid;
1599            mLeHandle = 0;
1600        }
1601
1602        public boolean scanStarted() {
1603            boolean started = false;
1604            synchronized(this) {
1605                if (mLeHandle == -1) return false;
1606
1607                int count = 0;
1608                // wait for callback registration and LE scan to start
1609                while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) {
1610                    try {
1611                        wait(LE_CALLBACK_REG_TIMEOUT);
1612                    } catch (InterruptedException e) {
1613                        Log.e(TAG, "Callback reg wait interrupted: " + e);
1614                    }
1615                    count++;
1616                }
1617                started = (mLeHandle > 0);
1618            }
1619            return started;
1620        }
1621
1622        public void stopLeScan() {
1623            synchronized(this) {
1624                if (mLeHandle <= 0) {
1625                    Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
1626                    return;
1627                }
1628                BluetoothAdapter adapter = mBluetoothAdapter.get();
1629                if (adapter != null) {
1630                    try {
1631                        IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt();
1632                        iGatt.stopScan(mLeHandle, false);
1633                        iGatt.unregisterClient(mLeHandle);
1634                    } catch (RemoteException e) {
1635                        Log.e(TAG, "Failed to stop scan and unregister" + e);
1636                    }
1637                } else {
1638                    Log.e(TAG, "stopLeScan, BluetoothAdapter is null");
1639                }
1640                mLeHandle = -1;
1641                notifyAll();
1642            }
1643        }
1644
1645        /**
1646         * Application interface registered - app is ready to go
1647         */
1648        public void onClientRegistered(int status, int clientIf) {
1649            if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status +
1650                           " clientIf=" + clientIf);
1651            synchronized(this) {
1652                if (mLeHandle == -1) {
1653                    if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled");
1654                }
1655
1656                if (status == BluetoothGatt.GATT_SUCCESS) {
1657                    mLeHandle = clientIf;
1658                    IBluetoothGatt iGatt = null;
1659                    try {
1660                        BluetoothAdapter adapter = mBluetoothAdapter.get();
1661                        if (adapter != null) {
1662                            iGatt = adapter.getBluetoothManager().getBluetoothGatt();
1663                            if (mScanFilter == null) {
1664                                iGatt.startScan(mLeHandle, false);
1665                            } else {
1666                                ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length];
1667                                for(int i = 0; i != uuids.length; ++i) {
1668                                    uuids[i] = new ParcelUuid(mScanFilter[i]);
1669                                }
1670                                iGatt.startScanWithUuids(mLeHandle, false, uuids);
1671                            }
1672                        } else {
1673                            Log.e(TAG, "onClientRegistered, BluetoothAdapter null");
1674                            mLeHandle = -1;
1675                        }
1676                    } catch (RemoteException e) {
1677                        Log.e(TAG, "fail to start le scan: " + e);
1678                        mLeHandle = -1;
1679                    }
1680                    if (mLeHandle == -1) {
1681                        // registration succeeded but start scan failed
1682                        if (iGatt != null) {
1683                            try {
1684                                iGatt.unregisterClient(mLeHandle);
1685                            } catch (RemoteException e) {
1686                                Log.e(TAG, "fail to unregister callback: " + mLeHandle +
1687                                      " error: " + e);
1688                            }
1689                        }
1690                    }
1691                } else {
1692                    // registration failed
1693                    mLeHandle = -1;
1694                }
1695                notifyAll();
1696            }
1697        }
1698
1699        public void onClientConnectionState(int status, int clientIf,
1700                                            boolean connected, String address) {
1701            // no op
1702        }
1703
1704        /**
1705         * Callback reporting an LE scan result.
1706         * @hide
1707         */
1708        public void onScanResult(String address, int rssi, byte[] advData) {
1709            if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
1710
1711            // Check null in case the scan has been stopped
1712            synchronized(this) {
1713                if (mLeHandle <= 0) return;
1714            }
1715            try {
1716                BluetoothAdapter adapter = mBluetoothAdapter.get();
1717                if (adapter == null) {
1718                    Log.d(TAG, "onScanResult, BluetoothAdapter null");
1719                    return;
1720                }
1721                mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData);
1722            } catch (Exception ex) {
1723                Log.w(TAG, "Unhandled exception: " + ex);
1724            }
1725        }
1726
1727        public void onGetService(String address, int srvcType,
1728                                 int srvcInstId, ParcelUuid srvcUuid) {
1729            // no op
1730        }
1731
1732        public void onGetIncludedService(String address, int srvcType,
1733                                         int srvcInstId, ParcelUuid srvcUuid,
1734                                         int inclSrvcType, int inclSrvcInstId,
1735                                         ParcelUuid inclSrvcUuid) {
1736            // no op
1737        }
1738
1739        public void onGetCharacteristic(String address, int srvcType,
1740                                        int srvcInstId, ParcelUuid srvcUuid,
1741                                        int charInstId, ParcelUuid charUuid,
1742                                        int charProps) {
1743            // no op
1744        }
1745
1746        public void onGetDescriptor(String address, int srvcType,
1747                                    int srvcInstId, ParcelUuid srvcUuid,
1748                                    int charInstId, ParcelUuid charUuid,
1749                                    int descInstId, ParcelUuid descUuid) {
1750            // no op
1751        }
1752
1753        public void onSearchComplete(String address, int status) {
1754            // no op
1755        }
1756
1757        public void onCharacteristicRead(String address, int status, int srvcType,
1758                                         int srvcInstId, ParcelUuid srvcUuid,
1759                                         int charInstId, ParcelUuid charUuid, byte[] value) {
1760            // no op
1761        }
1762
1763        public void onCharacteristicWrite(String address, int status, int srvcType,
1764                                          int srvcInstId, ParcelUuid srvcUuid,
1765                                          int charInstId, ParcelUuid charUuid) {
1766            // no op
1767        }
1768
1769        public void onNotify(String address, int srvcType,
1770                             int srvcInstId, ParcelUuid srvcUuid,
1771                             int charInstId, ParcelUuid charUuid,
1772                             byte[] value) {
1773            // no op
1774        }
1775
1776        public void onDescriptorRead(String address, int status, int srvcType,
1777                                     int srvcInstId, ParcelUuid srvcUuid,
1778                                     int charInstId, ParcelUuid charUuid,
1779                                     int descInstId, ParcelUuid descrUuid, byte[] value) {
1780            // no op
1781        }
1782
1783        public void onDescriptorWrite(String address, int status, int srvcType,
1784                                      int srvcInstId, ParcelUuid srvcUuid,
1785                                      int charInstId, ParcelUuid charUuid,
1786                                      int descInstId, ParcelUuid descrUuid) {
1787            // no op
1788        }
1789
1790        public void onExecuteWrite(String address, int status) {
1791            // no op
1792        }
1793
1794        public void onReadRemoteRssi(String address, int rssi, int status) {
1795            // no op
1796        }
1797
1798        public void onListen(int status) {
1799            // no op
1800        }
1801    }
1802
1803}
1804